StringValue as key leads to IllegalStateException

248 views
Skip to first unread message

Alexander Bischof

unread,
Feb 6, 2016, 1:45:25 AM2/6/16
to Chronicle
Hi,

i just started having a look at chroniclemap (3.4.2-beta) and tried to change the postalcode example to make use of StringValue as a key. Unfortunately i get this error:

StringValue averageKey = newHeapInstance(StringValue.class);
averageKey.setValue(new StringBuffer("Amsterdam")); //<--- error

ChronicleMap<StringValue, PostalCodeRange> cityPostalCodes = of(StringValue.class, PostalCodeRange.class)
 
.averageKey(averageKey)
 
.entries(50_000)
 
.create();


Exception in thread "main" java.lang.IllegalArgumentException: java.lang.IllegalStateException: different field types in methods of the field value: class java.lang.String interface java.lang.CharSequence
	at net.openhft.chronicle.values.ValueModel.acquire(ValueModel.java:42)
	at net.openhft.chronicle.values.Values.heapClassFor(Values.java:46)
	at net.openhft.chronicle.values.Values.newHeapInstance(Values.java:30)

I have seen that chronicle values is still alpha but that error looks a little bit odd to me.

Kind regards
Alex

Roman Leventov

unread,
Feb 6, 2016, 4:42:38 AM2/6/16
to java-ch...@googlegroups.com
I suppose you are using net.openhft.chronicle.core.values.StringValue interface. This interface is moved from old Java-Lang project, which had "data value generation" mechanishm (DataValueClasses), very similar to Chronicle-Values, but incompatible in some details. One of incompatibilities is that Chronicle-Values require getter return type and setter parameter type to be the same -- either CharSequence, String, or other type. Another incompatibility affecting this case, Chronicle-Values require CharSequence and String fields to be annotated with @MaxUtf8Length(N), with explicit max lengths specified. So net.openhft.chronicle.core.values.StringValue is not eligible for Chronicle-Values generation (is not a value interface).

See https://github.com/OpenHFT/Chronicle-Values#string-or-charsequence

There is no pre-defined value interface equivalent for net.openhft.chronicle.core.values.StringValue for the same reason -- we don't know, what MaxUtf8Length do you need. So you could define an interface yourself:

interface MyStringValue {
  CharSequence getValue();
  void setValue(@NotNull @MaxUtf8Length(MAX_VALUE_LENGTH) CharSequence value);
}

ChronicleMap<MyStringValue, PostalCodeRange> cityPostalCodes = ChronicleMap.
.of(MyStringValue.class, PostalCodeRange.class)
 
.entries(50_000)
 
.create();


Note that you don't need to specify averageKey(), because values (instances of value interfaces) are of fixed-length, and ChronicleMap knows about it. If your keys or values are of class that is not generally fixed-length (e. g. CharSequence), but in some ChronicleMap's domain they are fixed-length (i. e. 64-bit hashes in hex form, all of 16 characters), you should use constant[Key/Value]SizeBySample().

Note that for making values fixed-length, CharSequence and String fields always take the maximum number of bytes, specified in @MaxUtf8Length() annotation. So if you have @MaxUtf8Length(100), but most values of the CharSequence field are 10 chars long, you are wasting a lot of space.

I don't see much sense in having ChronicleMap's keys or values of StringValue (some kind of MyStringValue, that you defined yourself) rather than plain CharSequence. In Chronicle Map 3 tutorial, value interfaces are advocated as more caching/reusability - friendly, but it mostly comes to such examples as Integer/IntValue, because Integer is not reusable, IntValue is reusable. But if you have Chronicle Map's keys or values of CharSequence (but not String!) class, they are reuable as well as any kind of StringValue.

I. e. the examples in Chronicle Map 3 tutorial use mostly CharSequence keys not by accident. I have strived to make them most idiomatic and efficient for each given use case.

The only purpose I see to use StringValue, is to force size alignment (i. e. you puprosely introduce internal fragmentation, as noted three paragraphs above), in order to make all entries equal in size, to reduce external fragmentation, if you heavily remove/insert entries into ChronicleMap. BTW you could achieve similar effect by specifying sufficiently large .actualChunkSize() in ChronicleMapBuilder configuration.

Hope this helps!



--
You received this message because you are subscribed to the Google Groups "Chronicle" group.
To unsubscribe from this group and stop receiving emails from it, send an email to java-chronicl...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alexander Bischof

unread,
Feb 6, 2016, 4:53:58 PM2/6/16
to Chronicle
Hello Roman,

thank you for your good reply. I had not recognized that there is no pre-defined StringValue. I just saw LongValue in the example and gave StringValue a try.

Kind regards
Alex
Reply all
Reply to author
Forward
0 new messages