Skip to content

Commit 03fcb63

Browse files
committed
Reapply "Merge pull request #4541 from eXistSolutions/field-perf-revised"
This reverts commit b61b7d4.
1 parent a623725 commit 03fcb63

File tree

18 files changed

+894
-242
lines changed

18 files changed

+894
-242
lines changed

exist-core/src/main/java/org/exist/storage/ValueIndexFactory.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ public final static byte[] serialize(final Indexable value, final int offset) th
127127
return serialize(value, offset, true);
128128
}
129129

130+
// TODO(AR) switch implementation to various serialize methods in the AtomicValues (requires major version bump)
130131
public final static byte[] serialize(final Indexable value, final int offset, final boolean caseSensitive) throws EXistException {
131132
/* xs:string */
132133
if (Type.subTypeOf(value.getType(), Type.STRING)) {

exist-core/src/main/java/org/exist/util/ByteConversion.java

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
*/
2222
package org.exist.util;
2323

24+
import java.nio.ByteBuffer;
25+
2426
/**
2527
* A collection of static methods to write integer values from/to a
2628
* byte array.
@@ -64,6 +66,27 @@ public final static int byteToIntH(final byte[] data, final int start ) {
6466
( ( data[start] & 0xff ) << 24 );
6567
}
6668

69+
/**
70+
* Read an integer value from the specified byte buffer.
71+
*
72+
* This version of the method reads the highest byte first.
73+
*
74+
* @param buf the byte buffer to read from
75+
*
76+
* @return the integer
77+
*/
78+
public final static int byteToIntH(final ByteBuffer buf) {
79+
final byte b0 = buf.get();
80+
final byte b1 = buf.get();
81+
final byte b2 = buf.get();
82+
final byte b3 = buf.get();
83+
84+
return (b3 & 0xff) |
85+
((b2 & 0xff) << 8) |
86+
((b1 & 0xff) << 16) |
87+
((b0 & 0xff) << 24);
88+
}
89+
6790
/**
6891
* Read a long value from the specified byte array, starting at start.
6992
*
@@ -83,6 +106,33 @@ public final static long byteToLong( final byte[] data, final int start ) {
83106
( ( (long) data[start + 7] ) & 0xffL );
84107
}
85108

109+
/**
110+
* Read a long value from the specified byte buffer.
111+
*
112+
* @param buf the byte buffer to read from
113+
*
114+
* @return the long integer
115+
*/
116+
public final static long byteToLong(final ByteBuffer buf) {
117+
final byte b0 = buf.get();
118+
final byte b1 = buf.get();
119+
final byte b2 = buf.get();
120+
final byte b3 = buf.get();
121+
final byte b4 = buf.get();
122+
final byte b5 = buf.get();
123+
final byte b6 = buf.get();
124+
final byte b7 = buf.get();
125+
126+
return ((((long) b0) & 0xffL) << 56) |
127+
((((long) b1) & 0xffL) << 48) |
128+
((((long) b2) & 0xffL) << 40) |
129+
((((long) b3) & 0xffL) << 32) |
130+
((((long) b4) & 0xffL) << 24) |
131+
((((long) b5) & 0xffL) << 16) |
132+
((((long) b6) & 0xffL) << 8) |
133+
(((long) b7) & 0xffL);
134+
}
135+
86136
/**
87137
* Read a short value from the specified byte array, starting at start.
88138
*
@@ -114,6 +164,21 @@ public final static short byteToShortH( final byte[] data, final int start ) {
114164
( data[start + 1] & 0xff ) );
115165
}
116166

167+
/**
168+
* Read a short value from the specified byte array, starting at start.
169+
*
170+
* This version of the method reads the highest byte first.
171+
*
172+
* @param buf the byte buffer to read from
173+
*
174+
* @return the short integer
175+
*/
176+
public final static short byteToShortH(final ByteBuffer buf) {
177+
final byte b0 = buf.get();
178+
final byte b1 = buf.get();
179+
return (short) (((b0 & 0xff) << 8) | (b1 & 0xff));
180+
}
181+
117182
/**
118183
* Write an int value to the specified byte array. The first byte is written
119184
* into the location specified by start.
@@ -134,7 +199,22 @@ public final static byte[] intToByte( final int v, final byte[] data, final int
134199
}
135200

136201
/**
137-
* Write an int value to the specified byte array. The first byte is written
202+
* Write an int value to the specified byte array.
203+
*
204+
* This version of the method writes the highest byte first.
205+
*
206+
* @param v the value
207+
* @param buf the byte buffer to write into
208+
*/
209+
public final static void intToByteH(final int v, final ByteBuffer buf) {
210+
buf.put((byte) ((v >>> 24) & 0xff));
211+
buf.put((byte) ((v >>> 16) & 0xff));
212+
buf.put((byte) ((v >>> 8) & 0xff));
213+
buf.put((byte) ((v >>> 0) & 0xff));
214+
}
215+
216+
/**
217+
* Write an int value to the specified byte buffer. The first byte is written
138218
* into the location specified by start.
139219
*
140220
* This version of the method writes the highest byte first.
@@ -173,6 +253,22 @@ public final static byte[] longToByte( final long v, final byte[] data, final in
173253
return data;
174254
}
175255

256+
/**
257+
* Write a long value to the specified byte buffer.
258+
*
259+
* @param v the value
260+
* @param buf the byte buffer to write into
261+
*/
262+
public final static void longToByte(final long v, final ByteBuffer buf) {
263+
buf.put((byte) ((v >>> 56) & 0xff));
264+
buf.put((byte) ((v >>> 48) & 0xff));
265+
buf.put((byte) ((v >>> 40) & 0xff));
266+
buf.put((byte) ((v >>> 32) & 0xff));
267+
buf.put((byte) ((v >>> 24) & 0xff));
268+
buf.put((byte) ((v >>> 16) & 0xff));
269+
buf.put((byte) ((v >>> 8) & 0xff));
270+
buf.put((byte) ((v >>> 0) & 0xff));
271+
}
176272

177273
/**
178274
* Write an int value to a newly allocated byte array.
@@ -228,5 +324,19 @@ public final static byte[] shortToByteH( final short v, final byte[] data, final
228324
data[start] = (byte) ( ( v >>> 8 ) & 0xff );
229325
return data;
230326
}
327+
328+
/**
329+
* Write a short value to the specified byte array.
330+
*
331+
* This version writes the highest byte first.
332+
*
333+
* @param v the value
334+
* @param buf the byte buffer to write into
335+
*/
336+
public final static void shortToByteH(final short v, final ByteBuffer buf) {
337+
buf.put( (byte) ((v >>> 8) & 0xff));
338+
buf.put((byte) ((v >>> 0) & 0xff));
339+
340+
}
231341
}
232342

exist-core/src/main/java/org/exist/xquery/value/DateTimeValue.java

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
*/
2222
package org.exist.xquery.value;
2323

24+
import org.exist.util.ByteConversion;
2425
import org.exist.xquery.ErrorCodes;
2526
import org.exist.xquery.Expression;
2627
import org.exist.xquery.XPathException;
2728

2829
import javax.xml.datatype.DatatypeConstants;
2930
import javax.xml.datatype.XMLGregorianCalendar;
3031
import javax.xml.namespace.QName;
32+
import java.nio.ByteBuffer;
3133
import java.util.Date;
3234
import java.util.GregorianCalendar;
3335

@@ -39,6 +41,8 @@
3941
*/
4042
public class DateTimeValue extends AbstractDateTimeValue {
4143

44+
public static final int SERIALIZED_SIZE = 13;
45+
4246
public DateTimeValue() throws XPathException {
4347
super(null, TimeUtils.getInstance().newXMLGregorianCalendar(new GregorianCalendar()));
4448
normalize();
@@ -67,6 +71,10 @@ public DateTimeValue(final Expression expression, Date date) {
6771
normalize();
6872
}
6973

74+
public DateTimeValue(final int year, final int month, final int day, final int hour, final int minute, final int second, final int millisecond, final int timezone) {
75+
super(TimeUtils.getInstance().newXMLGregorianCalendar(year, month, day, hour, minute, second, millisecond, timezone));
76+
}
77+
7078
public DateTimeValue(String dateTime) throws XPathException {
7179
this(null, dateTime);
7280
}
@@ -180,4 +188,64 @@ public Date getDate() {
180188
return calendar.toGregorianCalendar().getTime();
181189
}
182190

191+
@Override
192+
public <T> T toJavaObject(final Class<T> target) throws XPathException {
193+
if (target == byte[].class) {
194+
final ByteBuffer buf = ByteBuffer.allocate(SERIALIZED_SIZE);
195+
serialize(buf);
196+
return (T) buf.array();
197+
} else if (target == ByteBuffer.class) {
198+
final ByteBuffer buf = ByteBuffer.allocate(SERIALIZED_SIZE);
199+
serialize(buf);
200+
return (T) buf;
201+
} else {
202+
return super.toJavaObject(target);
203+
}
204+
}
205+
206+
/**
207+
* Serializes to a ByteBuffer.
208+
*
209+
* 13 bytes where: [0-3 (Year), 4 (Month), 5 (Day), 6 (Hour), 7 (Minute), 8 (Second), 9-10 (Milliseconds), 11-12 (Timezone)]
210+
*
211+
* @param buf the ByteBuffer to serialize to.
212+
*/
213+
public void serialize(final ByteBuffer buf) {
214+
ByteConversion.intToByteH(calendar.getYear(), buf);
215+
buf.put((byte) calendar.getMonth());
216+
buf.put((byte) calendar.getDay());
217+
buf.put((byte) calendar.getHour());
218+
buf.put((byte) calendar.getMinute());
219+
buf.put((byte) calendar.getSecond());
220+
221+
final int ms = calendar.getMillisecond();
222+
if (ms == DatatypeConstants.FIELD_UNDEFINED) {
223+
buf.putShort((short) 0);
224+
} else {
225+
ByteConversion.shortToByteH((short) ms, buf);
226+
}
227+
228+
// values for timezone range from -14*60 to 14*60, so we can use a short, but
229+
// need to choose a different value for FIELD_UNDEFINED, which is not the same as 0 (= UTC)
230+
final int timezone = calendar.getTimezone();
231+
ByteConversion.shortToByteH((short) (timezone == DatatypeConstants.FIELD_UNDEFINED ? Short.MAX_VALUE : timezone), buf);
232+
}
233+
234+
public static AtomicValue deserialize(final ByteBuffer buf) {
235+
final int year = ByteConversion.byteToIntH(buf);
236+
final int month = buf.get();
237+
final int day = buf.get();
238+
final int hour = buf.get();
239+
final int minute = buf.get();
240+
final int second = buf.get();
241+
242+
final int ms = ByteConversion.byteToShortH(buf);
243+
244+
int timezone = ByteConversion.byteToShortH(buf);
245+
if (timezone == Short.MAX_VALUE) {
246+
timezone = DatatypeConstants.FIELD_UNDEFINED;
247+
}
248+
249+
return new DateTimeValue(year, month, day, hour, minute, second, ms, timezone);
250+
}
183251
}

exist-core/src/main/java/org/exist/xquery/value/DateValue.java

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
*/
2222
package org.exist.xquery.value;
2323

24+
import org.exist.util.ByteConversion;
2425
import org.exist.xquery.ErrorCodes;
2526
import org.exist.xquery.Expression;
2627
import org.exist.xquery.XPathException;
2728

2829
import javax.xml.datatype.DatatypeConstants;
2930
import javax.xml.datatype.XMLGregorianCalendar;
3031
import javax.xml.namespace.QName;
32+
import java.nio.ByteBuffer;
3133
import java.util.GregorianCalendar;
3234

3335
/**
@@ -36,6 +38,8 @@
3638
*/
3739
public class DateValue extends AbstractDateTimeValue {
3840

41+
public static final int SERIALIZED_SIZE = 8;
42+
3943
public DateValue() throws XPathException {
4044
super(null, stripCalendar(TimeUtils.getInstance().newXMLGregorianCalendar(new GregorianCalendar())));
4145
}
@@ -67,6 +71,10 @@ public DateValue(final Expression expression, XMLGregorianCalendar calendar) thr
6771
super(expression, stripCalendar(cloneXMLGregorianCalendar(calendar)));
6872
}
6973

74+
public DateValue(final int year, final int month, final int day, final int timezone) {
75+
super(TimeUtils.getInstance().newXMLGregorianCalendarDate(year, month, day, timezone));
76+
}
77+
7078
private static XMLGregorianCalendar stripCalendar(XMLGregorianCalendar calendar) {
7179
calendar.setHour(DatatypeConstants.FIELD_UNDEFINED);
7280
calendar.setMinute(DatatypeConstants.FIELD_UNDEFINED);
@@ -134,4 +142,50 @@ public ComputableValue minus(ComputableValue other) throws XPathException {
134142
+ Type.getTypeName(other.getType()));
135143
}
136144
}
145+
146+
@Override
147+
public <T> T toJavaObject(final Class<T> target) throws XPathException {
148+
if (target == byte[].class) {
149+
final ByteBuffer buf = ByteBuffer.allocate(SERIALIZED_SIZE);
150+
serialize(buf);
151+
return (T) buf.array();
152+
} else if (target == ByteBuffer.class) {
153+
final ByteBuffer buf = ByteBuffer.allocate(SERIALIZED_SIZE);
154+
serialize(buf);
155+
return (T) buf;
156+
} else {
157+
return super.toJavaObject(target);
158+
}
159+
}
160+
161+
/**
162+
* Serializes to a ByteBuffer.
163+
*
164+
* 8 bytes where: [0-3 (Year), 4 (Month), 5 (Day), 6-7 (Timezone)]
165+
*
166+
* @param buf the ByteBuffer to serialize to.
167+
*/
168+
public void serialize(final ByteBuffer buf) {
169+
ByteConversion.intToByteH(calendar.getYear(), buf);
170+
buf.put((byte) calendar.getMonth());
171+
buf.put((byte) calendar.getDay());
172+
173+
// values for timezone range from -14*60 to 14*60, so we can use a short, but
174+
// need to choose a different value for FIELD_UNDEFINED, which is not the same as 0 (= UTC)
175+
final int timezone = calendar.getTimezone();
176+
ByteConversion.shortToByteH((short) (timezone == DatatypeConstants.FIELD_UNDEFINED ? Short.MAX_VALUE : timezone), buf);
177+
}
178+
179+
public static AtomicValue deserialize(final ByteBuffer buf) {
180+
final int year = ByteConversion.byteToIntH(buf);
181+
final int month = buf.get();
182+
final int day = buf.get();
183+
184+
int timezone = ByteConversion.byteToShortH(buf);
185+
if (timezone == Short.MAX_VALUE) {
186+
timezone = DatatypeConstants.FIELD_UNDEFINED;
187+
}
188+
189+
return new DateValue(year, month, day, timezone);
190+
}
137191
}

0 commit comments

Comments
 (0)