001: package org.garret.perst.impl;
002:
003: import org.garret.perst.*;
004:
005: import java.lang.reflect.*;
006: import java.util.*;
007: import java.util.ArrayList;
008:
009: class BtreeMultiFieldIndex<T extends IPersistent> extends Btree<T>
010: implements FieldIndex<T> {
011: String className;
012: String[] fieldName;
013: int[] types;
014:
015: transient Class cls;
016: transient Field[] fld;
017:
018: BtreeMultiFieldIndex() {
019: }
020:
021: BtreeMultiFieldIndex(Class cls, String[] fieldName, boolean unique) {
022: this .cls = cls;
023: this .unique = unique;
024: this .fieldName = fieldName;
025: this .className = ClassDescriptor.getClassName(cls);
026: locateFields();
027: type = ClassDescriptor.tpArrayOfByte;
028: types = new int[fieldName.length];
029: for (int i = 0; i < types.length; i++) {
030: types[i] = checkType(fld[i].getType());
031: }
032: }
033:
034: private final void locateFields() {
035: fld = new Field[fieldName.length];
036: for (int i = 0; i < fieldName.length; i++) {
037: fld[i] = ClassDescriptor.locateField(cls, fieldName[i]);
038: if (fld[i] == null) {
039: throw new StorageError(
040: StorageError.INDEXED_FIELD_NOT_FOUND, className
041: + "." + fieldName[i]);
042: }
043: }
044: }
045:
046: public Class getIndexedClass() {
047: return cls;
048: }
049:
050: public Field[] getKeyFields() {
051: return fld;
052: }
053:
054: public void onLoad() {
055: cls = ClassDescriptor.loadClass(getStorage(), className);
056: locateFields();
057: }
058:
059: int compareByteArrays(byte[] key, byte[] item, int offs, int lengtn) {
060: int o1 = 0;
061: int o2 = offs;
062: byte[] a1 = key;
063: byte[] a2 = item;
064: for (int i = 0; i < fld.length && o1 < key.length; i++) {
065: int diff = 0;
066: switch (types[i]) {
067: case ClassDescriptor.tpBoolean:
068: case ClassDescriptor.tpByte:
069: diff = a1[o1++] - a2[o2++];
070: break;
071: case ClassDescriptor.tpShort:
072: diff = Bytes.unpack2(a1, o1) - Bytes.unpack2(a2, o2);
073: o1 += 2;
074: o2 += 2;
075: break;
076: case ClassDescriptor.tpChar:
077: diff = (char) Bytes.unpack2(a1, o1)
078: - (char) Bytes.unpack2(a2, o2);
079: o1 += 2;
080: o2 += 2;
081: break;
082: case ClassDescriptor.tpInt:
083: case ClassDescriptor.tpObject:
084: case ClassDescriptor.tpEnum: {
085: int i1 = Bytes.unpack4(a1, o1);
086: int i2 = Bytes.unpack4(a2, o2);
087: diff = i1 < i2 ? -1 : i1 == i2 ? 0 : 1;
088: o1 += 4;
089: o2 += 4;
090: break;
091: }
092: case ClassDescriptor.tpLong:
093: case ClassDescriptor.tpDate: {
094: long l1 = Bytes.unpack8(a1, o1);
095: long l2 = Bytes.unpack8(a2, o2);
096: diff = l1 < l2 ? -1 : l1 == l2 ? 0 : 1;
097: o1 += 8;
098: o2 += 8;
099: break;
100: }
101: case ClassDescriptor.tpFloat: {
102: float f1 = Float.intBitsToFloat(Bytes.unpack4(a1, o1));
103: float f2 = Float.intBitsToFloat(Bytes.unpack4(a2, o2));
104: diff = f1 < f2 ? -1 : f1 == f2 ? 0 : 1;
105: o1 += 4;
106: o2 += 4;
107: break;
108: }
109: case ClassDescriptor.tpDouble: {
110: double d1 = Double.longBitsToDouble(Bytes.unpack8(a1,
111: o1));
112: double d2 = Double.longBitsToDouble(Bytes.unpack8(a2,
113: o2));
114: diff = d1 < d2 ? -1 : d1 == d2 ? 0 : 1;
115: o1 += 8;
116: o2 += 8;
117: break;
118: }
119: case ClassDescriptor.tpString: {
120: int len1 = Bytes.unpack4(a1, o1);
121: int len2 = Bytes.unpack4(a2, o2);
122: o1 += 4;
123: o2 += 4;
124: int len = len1 < len2 ? len1 : len2;
125: while (--len >= 0) {
126: diff = (char) Bytes.unpack2(a1, o1)
127: - (char) Bytes.unpack2(a2, o2);
128: if (diff != 0) {
129: return diff;
130: }
131: o1 += 2;
132: o2 += 2;
133: }
134: diff = len1 - len2;
135: break;
136: }
137: case ClassDescriptor.tpArrayOfByte: {
138: int len1 = Bytes.unpack4(a1, o1);
139: int len2 = Bytes.unpack4(a2, o2);
140: o1 += 4;
141: o2 += 4;
142: int len = len1 < len2 ? len1 : len2;
143: while (--len >= 0) {
144: diff = a1[o1++] - a2[o2++];
145: if (diff != 0) {
146: return diff;
147: }
148: }
149: diff = len1 - len2;
150: break;
151: }
152: default:
153: Assert.failed("Invalid type");
154: }
155: if (diff != 0) {
156: return diff;
157: }
158: }
159: return 0;
160: }
161:
162: String convertString(Object s) {
163: return (String) s;
164: }
165:
166: Object unpackByteArrayKey(Page pg, int pos) {
167: int offs = BtreePage.firstKeyOffs
168: + BtreePage.getKeyStrOffs(pg, pos);
169: byte[] data = pg.data;
170: Object values[] = new Object[fld.length];
171:
172: for (int i = 0; i < fld.length; i++) {
173: Object v = null;
174: switch (types[i]) {
175: case ClassDescriptor.tpBoolean:
176: v = Boolean.valueOf(data[offs++] != 0);
177: break;
178: case ClassDescriptor.tpByte:
179: v = new Byte(data[offs++]);
180: break;
181: case ClassDescriptor.tpShort:
182: v = new Short(Bytes.unpack2(data, offs));
183: offs += 2;
184: break;
185: case ClassDescriptor.tpChar:
186: v = new Character((char) Bytes.unpack2(data, offs));
187: offs += 2;
188: break;
189: case ClassDescriptor.tpInt:
190: v = new Integer(Bytes.unpack4(data, offs));
191: offs += 4;
192: break;
193: case ClassDescriptor.tpObject: {
194: int oid = Bytes.unpack4(data, offs);
195: v = oid == 0 ? null : ((StorageImpl) getStorage())
196: .lookupObject(oid, null);
197: offs += 4;
198: break;
199: }
200: case ClassDescriptor.tpLong:
201: v = new Long(Bytes.unpack8(data, offs));
202: offs += 8;
203: break;
204: case ClassDescriptor.tpEnum:
205: v = fld[i].getType().getEnumConstants()[Bytes.unpack4(
206: data, offs)];
207: offs += 4;
208: break;
209: case ClassDescriptor.tpDate: {
210: long msec = Bytes.unpack8(data, offs);
211: v = msec == -1 ? null : new Date(msec);
212: offs += 8;
213: break;
214: }
215: case ClassDescriptor.tpFloat:
216: v = new Float(Float.intBitsToFloat(Bytes.unpack4(data,
217: offs)));
218: offs += 4;
219: break;
220: case ClassDescriptor.tpDouble:
221: v = new Double(Double.longBitsToDouble(Bytes.unpack8(
222: data, offs)));
223: offs += 8;
224: break;
225: case ClassDescriptor.tpString: {
226: int len = Bytes.unpack4(data, offs);
227: offs += 4;
228: char[] sval = new char[len];
229: for (int j = 0; j < len; j++) {
230: sval[j] = (char) Bytes.unpack2(data, offs);
231: offs += 2;
232: }
233: v = new String(sval);
234: break;
235: }
236: case ClassDescriptor.tpArrayOfByte: {
237: int len = Bytes.unpack4(data, offs);
238: offs += 4;
239: byte[] bval = new byte[len];
240: System.arraycopy(data, offs, bval, 0, len);
241: offs += len;
242: break;
243: }
244: default:
245: Assert.failed("Invalid type");
246: }
247: values[i] = v;
248: }
249: return values;
250: }
251:
252: private Key extractKey(IPersistent obj) {
253: try {
254: ByteBuffer buf = new ByteBuffer();
255: int dst = 0;
256: for (int i = 0; i < fld.length; i++) {
257: Field f = (Field) fld[i];
258: switch (types[i]) {
259: case ClassDescriptor.tpBoolean:
260: buf.extend(dst + 1);
261: buf.arr[dst++] = (byte) (f.getBoolean(obj) ? 1 : 0);
262: break;
263: case ClassDescriptor.tpByte:
264: buf.extend(dst + 1);
265: buf.arr[dst++] = f.getByte(obj);
266: break;
267: case ClassDescriptor.tpShort:
268: buf.extend(dst + 2);
269: Bytes.pack2(buf.arr, dst, f.getShort(obj));
270: dst += 2;
271: break;
272: case ClassDescriptor.tpChar:
273: buf.extend(dst + 2);
274: Bytes.pack2(buf.arr, dst, (short) f.getChar(obj));
275: dst += 2;
276: break;
277: case ClassDescriptor.tpInt:
278: buf.extend(dst + 4);
279: Bytes.pack4(buf.arr, dst, f.getInt(obj));
280: dst += 4;
281: break;
282: case ClassDescriptor.tpObject: {
283: IPersistent p = (IPersistent) f.get(obj);
284: buf.extend(dst + 4);
285: if (p != null) {
286: if (!p.isPersistent()) {
287: getStorage().makePersistent(p);
288: }
289: Bytes.pack4(buf.arr, dst, p.getOid());
290: } else {
291: Bytes.pack4(buf.arr, dst, 0);
292: }
293: dst += 4;
294: break;
295: }
296: case ClassDescriptor.tpLong:
297: buf.extend(dst + 8);
298: Bytes.pack8(buf.arr, dst, f.getLong(obj));
299: dst += 8;
300: break;
301: case ClassDescriptor.tpDate: {
302: Date d = (Date) f.get(obj);
303: buf.extend(dst + 8);
304: Bytes.pack8(buf.arr, dst, d == null ? -1 : d
305: .getTime());
306: dst += 8;
307: break;
308: }
309: case ClassDescriptor.tpFloat:
310: buf.extend(dst + 4);
311: Bytes.pack4(buf.arr, dst, Float.floatToIntBits(f
312: .getFloat(obj)));
313: dst += 4;
314: break;
315: case ClassDescriptor.tpDouble:
316: buf.extend(dst + 8);
317: Bytes.pack8(buf.arr, dst, Double.doubleToLongBits(f
318: .getDouble(obj)));
319: dst += 8;
320: break;
321: case ClassDescriptor.tpEnum:
322: buf.extend(dst + 4);
323: Bytes.pack4(buf.arr, dst, ((Enum) f.get(obj))
324: .ordinal());
325: dst += 4;
326: break;
327: case ClassDescriptor.tpString: {
328: buf.extend(dst + 4);
329: String str = convertString(f.get(obj));
330: if (str != null) {
331: int len = str.length();
332: Bytes.pack4(buf.arr, dst, len);
333: dst += 4;
334: buf.extend(dst + len * 2);
335: for (int j = 0; j < len; j++) {
336: Bytes.pack2(buf.arr, dst, (short) str
337: .charAt(j));
338: dst += 2;
339: }
340: } else {
341: Bytes.pack4(buf.arr, dst, 0);
342: dst += 4;
343: }
344: break;
345: }
346: case ClassDescriptor.tpArrayOfByte: {
347: buf.extend(dst + 4);
348: byte[] arr = (byte[]) f.get(obj);
349: if (arr != null) {
350: int len = arr.length;
351: Bytes.pack4(buf.arr, dst, len);
352: dst += 4;
353: buf.extend(dst + len);
354: System.arraycopy(arr, 0, buf.arr, dst, len);
355: dst += len;
356: } else {
357: Bytes.pack4(buf.arr, dst, 0);
358: dst += 4;
359: }
360: break;
361: }
362: default:
363: Assert.failed("Invalid type");
364: }
365: }
366: return new Key(buf.toArray());
367: } catch (Exception x) {
368: throw new StorageError(StorageError.ACCESS_VIOLATION, x);
369: }
370: }
371:
372: private Key convertKey(Key key) {
373: if (key == null) {
374: return null;
375: }
376: if (key.type != ClassDescriptor.tpArrayOfObject) {
377: throw new StorageError(StorageError.INCOMPATIBLE_KEY_TYPE);
378: }
379: Object[] values = (Object[]) key.oval;
380: ByteBuffer buf = new ByteBuffer();
381: int dst = 0;
382: for (int i = 0; i < values.length; i++) {
383: Object v = values[i];
384: switch (types[i]) {
385: case ClassDescriptor.tpBoolean:
386: buf.extend(dst + 1);
387: buf.arr[dst++] = (byte) (((Boolean) v).booleanValue() ? 1
388: : 0);
389: break;
390: case ClassDescriptor.tpByte:
391: buf.extend(dst + 1);
392: buf.arr[dst++] = ((Number) v).byteValue();
393: break;
394: case ClassDescriptor.tpShort:
395: buf.extend(dst + 2);
396: Bytes.pack2(buf.arr, dst, ((Number) v).shortValue());
397: dst += 2;
398: break;
399: case ClassDescriptor.tpChar:
400: buf.extend(dst + 2);
401: Bytes.pack2(buf.arr, dst,
402: (v instanceof Number) ? ((Number) v)
403: .shortValue() : (short) ((Character) v)
404: .charValue());
405: dst += 2;
406: break;
407: case ClassDescriptor.tpInt:
408: buf.extend(dst + 4);
409: Bytes.pack4(buf.arr, dst, ((Number) v).intValue());
410: dst += 4;
411: break;
412: case ClassDescriptor.tpObject:
413: buf.extend(dst + 4);
414: Bytes.pack4(buf.arr, dst, v == null ? 0
415: : ((IPersistent) v).getOid());
416: dst += 4;
417: break;
418: case ClassDescriptor.tpLong:
419: buf.extend(dst + 8);
420: Bytes.pack8(buf.arr, dst, ((Number) v).longValue());
421: dst += 8;
422: break;
423: case ClassDescriptor.tpDate:
424: buf.extend(dst + 8);
425: Bytes.pack8(buf.arr, dst, v == null ? -1 : ((Date) v)
426: .getTime());
427: dst += 8;
428: break;
429: case ClassDescriptor.tpFloat:
430: buf.extend(dst + 4);
431: Bytes.pack4(buf.arr, dst, Float
432: .floatToIntBits(((Number) v).floatValue()));
433: dst += 4;
434: break;
435: case ClassDescriptor.tpDouble:
436: buf.extend(dst + 8);
437: Bytes.pack8(buf.arr, dst, Double
438: .doubleToLongBits(((Number) v).doubleValue()));
439: dst += 8;
440: break;
441: case ClassDescriptor.tpEnum:
442: buf.extend(dst + 4);
443: Bytes.pack4(buf.arr, dst, ((Enum) v).ordinal());
444: dst += 4;
445: break;
446: case ClassDescriptor.tpString: {
447: buf.extend(dst + 4);
448: if (v != null) {
449: String str = convertString(v);
450: int len = str.length();
451: Bytes.pack4(buf.arr, dst, len);
452: dst += 4;
453: buf.extend(dst + len * 2);
454: for (int j = 0; j < len; j++) {
455: Bytes
456: .pack2(buf.arr, dst, (short) str
457: .charAt(j));
458: dst += 2;
459: }
460: } else {
461: Bytes.pack4(buf.arr, dst, 0);
462: dst += 4;
463: }
464: break;
465: }
466: case ClassDescriptor.tpArrayOfByte: {
467: buf.extend(dst + 4);
468: if (v != null) {
469: byte[] arr = (byte[]) v;
470: int len = arr.length;
471: Bytes.pack4(buf.arr, dst, len);
472: dst += 4;
473: buf.extend(dst + len);
474: System.arraycopy(arr, 0, buf.arr, dst, len);
475: dst += len;
476: } else {
477: Bytes.pack4(buf.arr, dst, 0);
478: dst += 4;
479: }
480: break;
481: }
482: default:
483: Assert.failed("Invalid type");
484: }
485: }
486: return new Key(buf.toArray(), key.inclusion != 0);
487: }
488:
489: public boolean put(T obj) {
490: return super .put(extractKey(obj), obj);
491: }
492:
493: public T set(T obj) {
494: return super .set(extractKey(obj), obj);
495: }
496:
497: public void remove(T obj) {
498: super .remove(extractKey(obj), obj);
499: }
500:
501: public T remove(Key key) {
502: return super .remove(convertKey(key));
503: }
504:
505: public boolean containsObject(T obj) {
506: Key key = extractKey(obj);
507: if (unique) {
508: return super .get(key) != null;
509: } else {
510: IPersistent[] mbrs = get(key, key);
511: for (int i = 0; i < mbrs.length; i++) {
512: if (mbrs[i] == obj) {
513: return true;
514: }
515: }
516: return false;
517: }
518: }
519:
520: public boolean contains(T obj) {
521: Key key = extractKey(obj);
522: if (unique) {
523: return super .get(key) != null;
524: } else {
525: IPersistent[] mbrs = get(key, key);
526: for (int i = 0; i < mbrs.length; i++) {
527: if (mbrs[i].equals(obj)) {
528: return true;
529: }
530: }
531: return false;
532: }
533: }
534:
535: public void append(T obj) {
536: throw new StorageError(StorageError.UNSUPPORTED_INDEX_TYPE);
537: }
538:
539: public T[] get(Key from, Key till) {
540: ArrayList list = new ArrayList();
541: if (root != 0) {
542: BtreePage.find((StorageImpl) getStorage(), root,
543: convertKey(from), convertKey(till), this , height,
544: list);
545: }
546: return (T[]) list.toArray((T[]) Array.newInstance(cls, list
547: .size()));
548: }
549:
550: public T[] getPrefix(String prefix) {
551: throw new StorageError(StorageError.INCOMPATIBLE_KEY_TYPE);
552: }
553:
554: public T[] prefixSearch(String key) {
555: throw new StorageError(StorageError.INCOMPATIBLE_KEY_TYPE);
556: }
557:
558: public T[] toPersistentArray() {
559: T[] arr = (T[]) Array.newInstance(cls, nElems);
560: if (root != 0) {
561: BtreePage.traverseForward((StorageImpl) getStorage(), root,
562: type, height, arr, 0);
563: }
564: return arr;
565: }
566:
567: public T get(Key key) {
568: return super .get(convertKey(key));
569: }
570:
571: public IterableIterator<T> iterator(Key from, Key till, int order) {
572: return super
573: .iterator(convertKey(from), convertKey(till), order);
574: }
575:
576: public IterableIterator<Map.Entry<Object, T>> entryIterator(
577: Key from, Key till, int order) {
578: return super .entryIterator(convertKey(from), convertKey(till),
579: order);
580: }
581:
582: public IterableIterator<T> queryByExample(T obj) {
583: Key key = extractKey(obj);
584: return iterator(key, key, ASCENT_ORDER);
585: }
586:
587: public IterableIterator<T> select(String predicate) {
588: Query<T> query = new QueryImpl<T>(getStorage());
589: return query.select(cls, iterator(), predicate);
590: }
591:
592: public boolean isCaseInsensitive() {
593: return false;
594: }
595: }
596:
597: class BtreeCaseInsensitiveMultiFieldIndex<T extends IPersistent>
598: extends BtreeMultiFieldIndex<T> {
599: BtreeCaseInsensitiveMultiFieldIndex() {
600: }
601:
602: BtreeCaseInsensitiveMultiFieldIndex(Class cls, String[] fieldNames,
603: boolean unique) {
604: super (cls, fieldNames, unique);
605: }
606:
607: String convertString(Object s) {
608: return ((String) s).toLowerCase();
609: }
610:
611: public boolean isCaseInsensitive() {
612: return true;
613: }
614: }
|