internal void close() { lock (this) { file.Close(); hashTable = null; dirtyPages = null; lru = null; freePages = null; } }
internal static OldBtreeResult removeStrKey(Page pg, int r) { int len = getKeyStrSize(pg, r) * 2; int offs = getKeyStrOffs(pg, r); int size = getSize(pg); int nItems = getnItems(pg); if ((nItems + 1) * strKeySize >= keySpace) memcpy(pg, r, pg, r + 1, nItems - r - 1, strKeySize); else memcpy(pg, r, pg, r + 1, nItems - r, strKeySize); if (len != 0) { memcpy(pg, keySpace - size + len, pg, keySpace - size, size - keySpace + offs, 1); for (int i = nItems; --i >= 0; ) { if (getKeyStrOffs(pg, i) < offs) setKeyStrOffs(pg, i, getKeyStrOffs(pg, i) + len); } setSize(pg, size -= len); } setnItems(pg, nItems - 1); return size + strKeySize * nItems < keySpace / 2 ? OldBtreeResult.Underflow : OldBtreeResult.Done; }
internal void open(IFile f) { file = f; hashTable = new Page[poolSize]; dirtyPages = new Page[poolSize]; nDirtyPages = 0; lru = new LRU(); freePages = null; if (autoExtended) return; for (int i = poolSize; --i >= 0; ) { Page pg = new Page(); pg.next = freePages; freePages = pg; } }
internal void getStr(Page pg, int i) { int len = OldBtreePage.getKeyStrSize(pg, i); int offs = OldBtreePage.firstKeyOffs + OldBtreePage.getKeyStrOffs(pg, i); char[] sval = new char[len]; for (int j = 0; j < len; j++) { sval[j] = (char)Bytes.unpack2(pg.data, offs); offs += 2; } key = new Key(sval); }
internal void extract(Page pg, int offs, ClassDescriptor.FieldType type) { byte[] data = pg.data; switch (type) { case ClassDescriptor.FieldType.tpBoolean: key = new Key(data[offs] != 0); break; case ClassDescriptor.FieldType.tpSByte: key = new Key((sbyte)data[offs]); break; case ClassDescriptor.FieldType.tpByte: key = new Key(data[offs]); break; case ClassDescriptor.FieldType.tpShort: key = new Key(Bytes.unpack2(data, offs)); break; case ClassDescriptor.FieldType.tpUShort: key = new Key((ushort)Bytes.unpack2(data, offs)); break; case ClassDescriptor.FieldType.tpChar: key = new Key((char)Bytes.unpack2(data, offs)); break; case ClassDescriptor.FieldType.tpInt: key = new Key(Bytes.unpack4(data, offs)); break; case ClassDescriptor.FieldType.tpEnum: case ClassDescriptor.FieldType.tpUInt: case ClassDescriptor.FieldType.tpObject: case ClassDescriptor.FieldType.tpOid: key = new Key((uint)Bytes.unpack4(data, offs)); break; case ClassDescriptor.FieldType.tpLong: key = new Key(Bytes.unpack8(data, offs)); break; case ClassDescriptor.FieldType.tpDate: case ClassDescriptor.FieldType.tpULong: key = new Key((ulong)Bytes.unpack8(data, offs)); break; case ClassDescriptor.FieldType.tpFloat: key = new Key(Bytes.unpackF4(data, offs)); break; case ClassDescriptor.FieldType.tpDouble: key = new Key(Bytes.unpackF8(data, offs)); break; case ClassDescriptor.FieldType.tpGuid: key = new Key(Bytes.unpackGuid(data, offs)); break; case ClassDescriptor.FieldType.tpDecimal: key = new Key(Bytes.unpackDecimal(data, offs)); break; default: Debug.Assert(false, "Invalid type"); break; } }
internal static int getSize(Page pg) { return Bytes.unpack2(pg.data, 2); }
internal static int compactifyByteArrays(Page pg, int m) { int i, j, offs, len, n = getnItems(pg); int[] size = new int[keySpace + 1]; int[] index = new int[keySpace + 1]; if (m == 0) return n; int nZeroLengthArrays = 0; if (m < 0) { m = -m; for (i = 0; i < n - m; i++) { len = getKeyStrSize(pg, i); if (len != 0) { offs = getKeyStrOffs(pg, i); size[offs + len] = len; index[offs + len] = i; } else { nZeroLengthArrays += 1; } } for (; i < n; i++) { len = getKeyStrSize(pg, i); if (len != 0) { offs = getKeyStrOffs(pg, i); size[offs + len] = len; index[offs + len] = -1; } } } else { for (i = 0; i < m; i++) { len = getKeyStrSize(pg, i); if (len != 0) { offs = getKeyStrOffs(pg, i); size[offs + len] = len; index[offs + len] = -1; } } for (; i < n; i++) { len = getKeyStrSize(pg, i); if (len != 0) { offs = getKeyStrOffs(pg, i); size[offs + len] = len; index[offs + len] = i - m; } else { nZeroLengthArrays += 1; } setKeyStrOid(pg, i - m, getKeyStrOid(pg, i)); setKeyStrSize(pg, i - m, len); } setKeyStrOid(pg, i - m, getKeyStrOid(pg, i)); } int nItems = n -= m; n -= nZeroLengthArrays; for (offs = keySpace, i = offs; n != 0; i -= len) { len = size[i]; j = index[i]; if (j >= 0) { offs -= len; n -= 1; setKeyStrOffs(pg, j, offs); if (offs != i - len) memcpy(pg, offs, pg, i - len, len, 1); } } return nItems; }
internal static void setKeyStrSize(Page pg, int index, int size) { Bytes.pack2(pg.data, firstKeyOffs + index * 8 + 4, (short)size); }
internal static void setnItems(Page pg, int nItems) { Bytes.pack2(pg.data, 0, (short)nItems); }
internal static void setKeyStrOffs(Page pg, int index, int offs) { Bytes.pack2(pg.data, firstKeyOffs + index * 8 + 6, (short)offs); }
internal static void setKeyStrOid(Page pg, int index, int oid) { Bytes.pack4(pg.data, firstKeyOffs + index * 8, oid); }
internal static void setKeyStrChars(Page pg, int offs, char[] str) { int len = str.Length; for (int i = 0; i < len; i++) { Bytes.pack2(pg.data, firstKeyOffs + offs, (short)str[i]); offs += 2; } }
internal static void setKeyBytes(Page pg, int offs, byte[] bytes) { Array.Copy(bytes, 0, pg.data, firstKeyOffs + offs, bytes.Length); }
internal static OldBtreeResult replaceStrKey(DatabaseImpl db, Page pg, int r, OldBtreeKey ins, int height) { ins.oid = getKeyStrOid(pg, r); removeStrKey(pg, r); return insertStrKey(db, pg, r, ins, height); }
internal static int getnItems(Page pg) { return Bytes.unpack2(pg.data, 0); }
internal static void setReference(Page pg, int index, int oid) { Bytes.pack4(pg.data, firstKeyOffs + index * 4, oid); }
internal static int getReference(Page pg, int index) { return Bytes.unpack4(pg.data, firstKeyOffs + index * 4); }
internal static void setSize(Page pg, int size) { Bytes.pack2(pg.data, 2, (short)size); }
internal static OldBtreeResult handlePageUnderflow(DatabaseImpl db, Page pg, int r, ClassDescriptor.FieldType type, OldBtreeKey rem, int height) { int nItems = getnItems(pg); if (type == ClassDescriptor.FieldType.tpString) { Page a = db.putPage(getKeyStrOid(pg, r)); int an = getnItems(a); if (r < nItems) { // exists greater page Page b = db.getPage(getKeyStrOid(pg, r + 1)); int bn = getnItems(b); int merged_size = (an + bn) * strKeySize + getSize(a) + getSize(b); if (height != 1) { merged_size += getKeyStrSize(pg, r) * 2 + strKeySize * 2; } if (merged_size > keySpace) { // reallocation of nodes between pages a and b int i, j, k; db.pool.unfix(b); b = db.putPage(getKeyStrOid(pg, r + 1)); int size_a = getSize(a); int size_b = getSize(b); int addSize, subSize; if (height != 1) { addSize = getKeyStrSize(pg, r); subSize = getKeyStrSize(b, 0); } else { addSize = subSize = getKeyStrSize(b, 0); } i = 0; int prevDelta = (an * strKeySize + size_a) - (bn * strKeySize + size_b); while (true) { i += 1; int delta = ((an + i) * strKeySize + size_a + addSize * 2) - ((bn - i) * strKeySize + size_b - subSize * 2); if (delta >= 0) { if (delta >= -prevDelta) i -= 1; break; } size_a += addSize * 2; size_b -= subSize * 2; prevDelta = delta; if (height != 1) { addSize = subSize; subSize = getKeyStrSize(b, i); } else { addSize = subSize = getKeyStrSize(b, i); } } OldBtreeResult result = OldBtreeResult.Done; if (i > 0) { k = i; if (height != 1) { int len = getKeyStrSize(pg, r); setSize(a, getSize(a) + len * 2); setKeyStrOffs(a, an, keySpace - getSize(a)); setKeyStrSize(a, an, len); memcpy(a, getKeyStrOffs(a, an), pg, getKeyStrOffs(pg, r), len * 2, 1); k -= 1; an += 1; setKeyStrOid(a, an + k, getKeyStrOid(b, k)); setSize(b, getSize(b) - getKeyStrSize(b, k) * 2); } for (j = 0; j < k; j++) { int len = getKeyStrSize(b, j); setSize(a, getSize(a) + len * 2); setSize(b, getSize(b) - len * 2); setKeyStrOffs(a, an, keySpace - getSize(a)); setKeyStrSize(a, an, len); setKeyStrOid(a, an, getKeyStrOid(b, j)); memcpy(a, getKeyStrOffs(a, an), b, getKeyStrOffs(b, j), len * 2, 1); an += 1; } rem.getStr(b, i - 1); result = replaceStrKey(db, pg, r, rem, height); setnItems(a, an); setnItems(b, compactifyStrings(b, i)); } db.pool.unfix(a); db.pool.unfix(b); return result; } else { // merge page b to a if (height != 1) { int r_len = getKeyStrSize(pg, r); setKeyStrSize(a, an, r_len); setSize(a, getSize(a) + r_len * 2); setKeyStrOffs(a, an, keySpace - getSize(a)); memcpy(a, getKeyStrOffs(a, an), pg, getKeyStrOffs(pg, r), r_len * 2, 1); an += 1; setKeyStrOid(a, an + bn, getKeyStrOid(b, bn)); } for (int i = 0; i < bn; i++, an++) { setKeyStrSize(a, an, getKeyStrSize(b, i)); setKeyStrOffs(a, an, getKeyStrOffs(b, i) - getSize(a)); setKeyStrOid(a, an, getKeyStrOid(b, i)); } setSize(a, getSize(a) + getSize(b)); setnItems(a, an); memcpy(a, keySpace - getSize(a), b, keySpace - getSize(b), getSize(b), 1); db.pool.unfix(a); db.pool.unfix(b); db.freePage(getKeyStrOid(pg, r + 1)); setKeyStrOid(pg, r + 1, getKeyStrOid(pg, r)); return removeStrKey(pg, r); } } else { // page b is before a Page b = db.getPage(getKeyStrOid(pg, r - 1)); int bn = getnItems(b); int merged_size = (an + bn) * strKeySize + getSize(a) + getSize(b); if (height != 1) merged_size += getKeyStrSize(pg, r - 1) * 2 + strKeySize * 2; if (merged_size > keySpace) { // reallocation of nodes between pages a and b int i, j, k, len; db.pool.unfix(b); b = db.putPage(getKeyStrOid(pg, r - 1)); int size_a = getSize(a); int size_b = getSize(b); int addSize, subSize; if (height != 1) { addSize = getKeyStrSize(pg, r - 1); subSize = getKeyStrSize(b, bn - 1); } else { addSize = subSize = getKeyStrSize(b, bn - 1); } i = 0; int prevDelta = (an * strKeySize + size_a) - (bn * strKeySize + size_b); while (true) { i += 1; int delta = ((an + i) * strKeySize + size_a + addSize * 2) - ((bn - i) * strKeySize + size_b - subSize * 2); if (delta >= 0) { if (delta >= -prevDelta) i -= 1; break; } prevDelta = delta; size_a += addSize * 2; size_b -= subSize * 2; if (height != 1) { addSize = subSize; subSize = getKeyStrSize(b, bn - i - 1); } else { addSize = subSize = getKeyStrSize(b, bn - i - 1); } } OldBtreeResult result = OldBtreeResult.Done; if (i > 0) { k = i; Debug.Assert(i < bn); if (height != 1) { setSize(b, getSize(b) - getKeyStrSize(b, bn - k) * 2); memcpy(a, i, a, 0, an + 1, strKeySize); k -= 1; setKeyStrOid(a, k, getKeyStrOid(b, bn)); len = getKeyStrSize(pg, r - 1); setKeyStrSize(a, k, len); setSize(a, getSize(a) + len * 2); setKeyStrOffs(a, k, keySpace - getSize(a)); memcpy(a, getKeyStrOffs(a, k), pg, getKeyStrOffs(pg, r - 1), len * 2, 1); } else { memcpy(a, i, a, 0, an, strKeySize); } for (j = 0; j < k; j++) { len = getKeyStrSize(b, bn - k + j); setSize(a, getSize(a) + len * 2); setSize(b, getSize(b) - len * 2); setKeyStrOffs(a, j, keySpace - getSize(a)); setKeyStrSize(a, j, len); setKeyStrOid(a, j, getKeyStrOid(b, bn - k + j)); memcpy(a, getKeyStrOffs(a, j), b, getKeyStrOffs(b, bn - k + j), len * 2, 1); } an += i; setnItems(a, an); rem.getStr(b, bn - k - 1); result = replaceStrKey(db, pg, r - 1, rem, height); setnItems(b, compactifyStrings(b, -i)); } db.pool.unfix(a); db.pool.unfix(b); return result; } else { // merge page b to a if (height != 1) { memcpy(a, bn + 1, a, 0, an + 1, strKeySize); int len = getKeyStrSize(pg, r - 1); setKeyStrSize(a, bn, len); setSize(a, getSize(a) + len * 2); setKeyStrOffs(a, bn, keySpace - getSize(a)); setKeyStrOid(a, bn, getKeyStrOid(b, bn)); memcpy(a, getKeyStrOffs(a, bn), pg, getKeyStrOffs(pg, r - 1), len * 2, 1); an += 1; } else { memcpy(a, bn, a, 0, an, strKeySize); } for (int i = 0; i < bn; i++) { setKeyStrOid(a, i, getKeyStrOid(b, i)); setKeyStrSize(a, i, getKeyStrSize(b, i)); setKeyStrOffs(a, i, getKeyStrOffs(b, i) - getSize(a)); } an += bn; setnItems(a, an); setSize(a, getSize(a) + getSize(b)); memcpy(a, keySpace - getSize(a), b, keySpace - getSize(b), getSize(b), 1); db.pool.unfix(a); db.pool.unfix(b); db.freePage(getKeyStrOid(pg, r - 1)); return removeStrKey(pg, r - 1); } } } else if (type == ClassDescriptor.FieldType.tpArrayOfByte) { Page a = db.putPage(getKeyStrOid(pg, r)); int an = getnItems(a); if (r < nItems) { // exists greater page Page b = db.getPage(getKeyStrOid(pg, r + 1)); int bn = getnItems(b); int merged_size = (an + bn) * strKeySize + getSize(a) + getSize(b); if (height != 1) { merged_size += getKeyStrSize(pg, r) + strKeySize * 2; } if (merged_size > keySpace) { // reallocation of nodes between pages a and b int i, j, k; db.pool.unfix(b); b = db.putPage(getKeyStrOid(pg, r + 1)); int size_a = getSize(a); int size_b = getSize(b); int addSize, subSize; if (height != 1) { addSize = getKeyStrSize(pg, r); subSize = getKeyStrSize(b, 0); } else { addSize = subSize = getKeyStrSize(b, 0); } i = 0; int prevDelta = (an * strKeySize + size_a) - (bn * strKeySize + size_b); while (true) { i += 1; int delta = ((an + i) * strKeySize + size_a + addSize) - ((bn - i) * strKeySize + size_b - subSize); if (delta >= 0) { if (delta >= -prevDelta) i -= 1; break; } size_a += addSize; size_b -= subSize; prevDelta = delta; if (height != 1) { addSize = subSize; subSize = getKeyStrSize(b, i); } else { addSize = subSize = getKeyStrSize(b, i); } } OldBtreeResult result = OldBtreeResult.Done; if (i > 0) { k = i; if (height != 1) { int len = getKeyStrSize(pg, r); setSize(a, getSize(a) + len); setKeyStrOffs(a, an, keySpace - getSize(a)); setKeyStrSize(a, an, len); memcpy(a, getKeyStrOffs(a, an), pg, getKeyStrOffs(pg, r), len, 1); k -= 1; an += 1; setKeyStrOid(a, an + k, getKeyStrOid(b, k)); setSize(b, getSize(b) - getKeyStrSize(b, k)); } for (j = 0; j < k; j++) { int len = getKeyStrSize(b, j); setSize(a, getSize(a) + len); setSize(b, getSize(b) - len); setKeyStrOffs(a, an, keySpace - getSize(a)); setKeyStrSize(a, an, len); setKeyStrOid(a, an, getKeyStrOid(b, j)); memcpy(a, getKeyStrOffs(a, an), b, getKeyStrOffs(b, j), len, 1); an += 1; } rem.getByteArray(b, i - 1); result = replaceByteArrayKey(db, pg, r, rem, height); setnItems(a, an); setnItems(b, compactifyByteArrays(b, i)); } db.pool.unfix(a); db.pool.unfix(b); return result; } else { // merge page b to a if (height != 1) { int r_len = getKeyStrSize(pg, r); setKeyStrSize(a, an, r_len); setSize(a, getSize(a) + r_len); setKeyStrOffs(a, an, keySpace - getSize(a)); memcpy(a, getKeyStrOffs(a, an), pg, getKeyStrOffs(pg, r), r_len, 1); an += 1; setKeyStrOid(a, an + bn, getKeyStrOid(b, bn)); } for (int i = 0; i < bn; i++, an++) { setKeyStrSize(a, an, getKeyStrSize(b, i)); setKeyStrOffs(a, an, getKeyStrOffs(b, i) - getSize(a)); setKeyStrOid(a, an, getKeyStrOid(b, i)); } setSize(a, getSize(a) + getSize(b)); setnItems(a, an); memcpy(a, keySpace - getSize(a), b, keySpace - getSize(b), getSize(b), 1); db.pool.unfix(a); db.pool.unfix(b); db.freePage(getKeyStrOid(pg, r + 1)); setKeyStrOid(pg, r + 1, getKeyStrOid(pg, r)); return removeByteArrayKey(pg, r); } } else { // page b is before a Page b = db.getPage(getKeyStrOid(pg, r - 1)); int bn = getnItems(b); int merged_size = (an + bn) * strKeySize + getSize(a) + getSize(b); if (height != 1) merged_size += getKeyStrSize(pg, r - 1) + strKeySize * 2; if (merged_size > keySpace) { // reallocation of nodes between pages a and b int i, j, k, len; db.pool.unfix(b); b = db.putPage(getKeyStrOid(pg, r - 1)); int size_a = getSize(a); int size_b = getSize(b); int addSize, subSize; if (height != 1) { addSize = getKeyStrSize(pg, r - 1); subSize = getKeyStrSize(b, bn - 1); } else { addSize = subSize = getKeyStrSize(b, bn - 1); } i = 0; int prevDelta = (an * strKeySize + size_a) - (bn * strKeySize + size_b); while (true) { i += 1; int delta = ((an + i) * strKeySize + size_a + addSize) - ((bn - i) * strKeySize + size_b - subSize); if (delta >= 0) { if (delta >= -prevDelta) i -= 1; break; } prevDelta = delta; size_a += addSize; size_b -= subSize; if (height != 1) { addSize = subSize; subSize = getKeyStrSize(b, bn - i - 1); } else { addSize = subSize = getKeyStrSize(b, bn - i - 1); } } OldBtreeResult result = OldBtreeResult.Done; if (i > 0) { k = i; Debug.Assert(i < bn); if (height != 1) { setSize(b, getSize(b) - getKeyStrSize(b, bn - k)); memcpy(a, i, a, 0, an + 1, strKeySize); k -= 1; setKeyStrOid(a, k, getKeyStrOid(b, bn)); len = getKeyStrSize(pg, r - 1); setKeyStrSize(a, k, len); setSize(a, getSize(a) + len); setKeyStrOffs(a, k, keySpace - getSize(a)); memcpy(a, getKeyStrOffs(a, k), pg, getKeyStrOffs(pg, r - 1), len, 1); } else { memcpy(a, i, a, 0, an, strKeySize); } for (j = 0; j < k; j++) { len = getKeyStrSize(b, bn - k + j); setSize(a, getSize(a) + len); setSize(b, getSize(b) - len); setKeyStrOffs(a, j, keySpace - getSize(a)); setKeyStrSize(a, j, len); setKeyStrOid(a, j, getKeyStrOid(b, bn - k + j)); memcpy(a, getKeyStrOffs(a, j), b, getKeyStrOffs(b, bn - k + j), len, 1); } an += i; setnItems(a, an); rem.getByteArray(b, bn - k - 1); result = replaceByteArrayKey(db, pg, r - 1, rem, height); setnItems(b, compactifyByteArrays(b, -i)); } db.pool.unfix(a); db.pool.unfix(b); return result; } else { // merge page b to a if (height != 1) { memcpy(a, bn + 1, a, 0, an + 1, strKeySize); int len = getKeyStrSize(pg, r - 1); setKeyStrSize(a, bn, len); setSize(a, getSize(a) + len); setKeyStrOffs(a, bn, keySpace - getSize(a)); setKeyStrOid(a, bn, getKeyStrOid(b, bn)); memcpy(a, getKeyStrOffs(a, bn), pg, getKeyStrOffs(pg, r - 1), len, 1); an += 1; } else { memcpy(a, bn, a, 0, an, strKeySize); } for (int i = 0; i < bn; i++) { setKeyStrOid(a, i, getKeyStrOid(b, i)); setKeyStrSize(a, i, getKeyStrSize(b, i)); setKeyStrOffs(a, i, getKeyStrOffs(b, i) - getSize(a)); } an += bn; setnItems(a, an); setSize(a, getSize(a) + getSize(b)); memcpy(a, keySpace - getSize(a), b, keySpace - getSize(b), getSize(b), 1); db.pool.unfix(a); db.pool.unfix(b); db.freePage(getKeyStrOid(pg, r - 1)); return removeByteArrayKey(pg, r - 1); } } } else { Page a = db.putPage(getReference(pg, maxItems - r - 1)); int an = getnItems(a); int itemSize = ClassDescriptor.Sizeof[(int)type]; if (r < nItems) { // exists greater page Page b = db.getPage(getReference(pg, maxItems - r - 2)); int bn = getnItems(b); Debug.Assert(bn >= an); if (height != 1) { memcpy(a, an, pg, r, 1, itemSize); an += 1; bn += 1; } int merged_size = (an + bn) * (4 + itemSize); if (merged_size > keySpace) { // reallocation of nodes between pages a and b int i = bn - ((an + bn) >> 1); db.pool.unfix(b); b = db.putPage(getReference(pg, maxItems - r - 2)); memcpy(a, an, b, 0, i, itemSize); memcpy(b, 0, b, i, bn - i, itemSize); memcpy(a, maxItems - an - i, b, maxItems - i, i, 4); memcpy(b, maxItems - bn + i, b, maxItems - bn, bn - i, 4); memcpy(pg, r, a, an + i - 1, 1, itemSize); setnItems(b, getnItems(b) - i); setnItems(a, getnItems(a) + i); db.pool.unfix(a); db.pool.unfix(b); return OldBtreeResult.Done; } else { // merge page b to a memcpy(a, an, b, 0, bn, itemSize); memcpy(a, maxItems - an - bn, b, maxItems - bn, bn, 4); db.freePage(getReference(pg, maxItems - r - 2)); memcpy(pg, maxItems - nItems, pg, maxItems - nItems - 1, nItems - r - 1, 4); memcpy(pg, r, pg, r + 1, nItems - r - 1, itemSize); setnItems(a, getnItems(a) + bn); setnItems(pg, nItems - 1); db.pool.unfix(a); db.pool.unfix(b); return nItems * (itemSize + 4) < keySpace / 2 ? OldBtreeResult.Underflow : OldBtreeResult.Done; } } else { // page b is before a Page b = db.getPage(getReference(pg, maxItems - r)); int bn = getnItems(b); Debug.Assert(bn >= an); if (height != 1) { an += 1; bn += 1; } int merged_size = (an + bn) * (4 + itemSize); if (merged_size > keySpace) { // reallocation of nodes between pages a and b int i = bn - ((an + bn) >> 1); db.pool.unfix(b); b = db.putPage(getReference(pg, maxItems - r)); memcpy(a, i, a, 0, an, itemSize); memcpy(a, 0, b, bn - i, i, itemSize); memcpy(a, maxItems - an - i, a, maxItems - an, an, 4); memcpy(a, maxItems - i, b, maxItems - bn, i, 4); if (height != 1) { memcpy(a, i - 1, pg, r - 1, 1, itemSize); } memcpy(pg, r - 1, b, bn - i - 1, 1, itemSize); setnItems(b, getnItems(b) - i); setnItems(a, getnItems(a) + i); db.pool.unfix(a); db.pool.unfix(b); return OldBtreeResult.Done; } else { // merge page b to a memcpy(a, bn, a, 0, an, itemSize); memcpy(a, 0, b, 0, bn, itemSize); memcpy(a, maxItems - an - bn, a, maxItems - an, an, 4); memcpy(a, maxItems - bn, b, maxItems - bn, bn, 4); if (height != 1) memcpy(a, bn - 1, pg, r - 1, 1, itemSize); db.freePage(getReference(pg, maxItems - r)); setReference(pg, maxItems - r, getReference(pg, maxItems - r - 1)); setnItems(a, getnItems(a) + bn); setnItems(pg, nItems - 1); db.pool.unfix(a); db.pool.unfix(b); return nItems * (itemSize + 4) < keySpace / 2 ? OldBtreeResult.Underflow : OldBtreeResult.Done; } } } }
static int comparePrefix(string key, Page pg, int i) { int alen = key.Length; int blen = OldBtreePage.getKeyStrSize(pg, i); int minlen = alen < blen ? alen : blen; int offs = OldBtreePage.getKeyStrOffs(pg, i) + OldBtreePage.firstKeyOffs; byte[] b = pg.data; for (int j = 0; j < minlen; j++) { char c = (char)Bytes.unpack2(b, offs); int diff = key[j] - c; if (diff != 0) return diff; offs += 2; } return minlen - alen; }
internal void getByteArray(Page pg, int i) { int len = OldBtreePage.getKeyStrSize(pg, i); int offs = OldBtreePage.firstKeyOffs + OldBtreePage.getKeyStrOffs(pg, i); byte[] bval = new byte[len]; Array.Copy(pg.data, offs, bval, 0, len); key = new Key(bval); }
internal static int compare(Key key, Page pg, int i) { long i8; ulong u8; int i4; uint u4; float r4; double r8; switch (key.type) { case ClassDescriptor.FieldType.tpSByte: return (sbyte)key.ival - (sbyte)pg.data[OldBtreePage.firstKeyOffs + i]; case ClassDescriptor.FieldType.tpBoolean: case ClassDescriptor.FieldType.tpByte: return (byte)key.ival - pg.data[OldBtreePage.firstKeyOffs + i]; case ClassDescriptor.FieldType.tpShort: return (short)key.ival - Bytes.unpack2(pg.data, OldBtreePage.firstKeyOffs + i * 2); case ClassDescriptor.FieldType.tpUShort: return (ushort)key.ival - (ushort)Bytes.unpack2(pg.data, OldBtreePage.firstKeyOffs + i * 2); case ClassDescriptor.FieldType.tpChar: return (char)key.ival - (char)Bytes.unpack2(pg.data, OldBtreePage.firstKeyOffs + i * 2); case ClassDescriptor.FieldType.tpObject: case ClassDescriptor.FieldType.tpUInt: case ClassDescriptor.FieldType.tpOid: case ClassDescriptor.FieldType.tpEnum: u4 = (uint)Bytes.unpack4(pg.data, OldBtreePage.firstKeyOffs + i * 4); return (uint)key.ival < u4 ? -1 : (uint)key.ival == u4 ? 0 : 1; case ClassDescriptor.FieldType.tpInt: i4 = Bytes.unpack4(pg.data, OldBtreePage.firstKeyOffs + i * 4); return key.ival < i4 ? -1 : key.ival == i4 ? 0 : 1; case ClassDescriptor.FieldType.tpLong: i8 = Bytes.unpack8(pg.data, OldBtreePage.firstKeyOffs + i * 8); return key.lval < i8 ? -1 : key.lval == i8 ? 0 : 1; case ClassDescriptor.FieldType.tpDate: case ClassDescriptor.FieldType.tpULong: u8 = (ulong)Bytes.unpack8(pg.data, OldBtreePage.firstKeyOffs + i * 8); return (ulong)key.lval < u8 ? -1 : (ulong)key.lval == u8 ? 0 : 1; case ClassDescriptor.FieldType.tpFloat: r4 = Bytes.unpackF4(pg.data, OldBtreePage.firstKeyOffs + i * 4); return key.dval < r4 ? -1 : key.dval == r4 ? 0 : 1; case ClassDescriptor.FieldType.tpDouble: r8 = Bytes.unpackF8(pg.data, OldBtreePage.firstKeyOffs + i * 8); return key.dval < r8 ? -1 : key.dval == r8 ? 0 : 1; case ClassDescriptor.FieldType.tpDecimal: return key.dec.CompareTo(Bytes.unpackDecimal(pg.data, OldBtreePage.firstKeyOffs + i * 16)); case ClassDescriptor.FieldType.tpGuid: return key.guid.CompareTo(Bytes.unpackGuid(pg.data, OldBtreePage.firstKeyOffs + i * 16)); } Debug.Assert(false, "Invalid type"); return 0; }
internal void pack(Page pg, int i) { byte[] dst = pg.data; switch (key.type) { case ClassDescriptor.FieldType.tpBoolean: case ClassDescriptor.FieldType.tpSByte: case ClassDescriptor.FieldType.tpByte: dst[OldBtreePage.firstKeyOffs + i] = (byte)key.ival; break; case ClassDescriptor.FieldType.tpShort: case ClassDescriptor.FieldType.tpUShort: case ClassDescriptor.FieldType.tpChar: Bytes.pack2(dst, OldBtreePage.firstKeyOffs + i * 2, (short)key.ival); break; case ClassDescriptor.FieldType.tpInt: case ClassDescriptor.FieldType.tpUInt: case ClassDescriptor.FieldType.tpEnum: case ClassDescriptor.FieldType.tpObject: case ClassDescriptor.FieldType.tpOid: Bytes.pack4(dst, OldBtreePage.firstKeyOffs + i * 4, key.ival); break; case ClassDescriptor.FieldType.tpLong: case ClassDescriptor.FieldType.tpULong: case ClassDescriptor.FieldType.tpDate: Bytes.pack8(dst, OldBtreePage.firstKeyOffs + i * 8, key.lval); break; case ClassDescriptor.FieldType.tpFloat: Bytes.packF4(dst, OldBtreePage.firstKeyOffs + i * 4, (float)key.dval); break; case ClassDescriptor.FieldType.tpDouble: Bytes.packF8(dst, OldBtreePage.firstKeyOffs + i * 8, key.dval); break; case ClassDescriptor.FieldType.tpDecimal: Bytes.packDecimal(dst, OldBtreePage.firstKeyOffs + i * 16, key.dec); break; case ClassDescriptor.FieldType.tpGuid: Bytes.packGuid(dst, OldBtreePage.firstKeyOffs + i * 16, key.guid); break; default: Debug.Assert(false, "Invalid type"); break; } Bytes.pack4(dst, OldBtreePage.firstKeyOffs + (OldBtreePage.maxItems - i - 1) * 4, oid); }
internal static int compareStr(Key key, Page pg, int i) { char[] chars = null; string s = key.oval as string; if (s != null) chars = s.ToCharArray(); else chars = (char[])key.oval; int alen = chars.Length; int blen = OldBtreePage.getKeyStrSize(pg, i); int minlen = alen < blen ? alen : blen; int offs = OldBtreePage.getKeyStrOffs(pg, i) + OldBtreePage.firstKeyOffs; byte[] b = pg.data; for (int j = 0; j < minlen; j++) { int diff = chars[j] - (char)Bytes.unpack2(b, offs); if (diff != 0) return diff; offs += 2; } return alen - blen; }
internal void modify(Page pg) { lock (this) { Debug.Assert(pg.accessCount > 0); if ((pg.state & Page.psDirty) == 0) { Debug.Assert(!flushing); pg.state |= Page.psDirty; if (nDirtyPages >= dirtyPages.Length) { Page[] newDirtyPages = new Page[nDirtyPages * 2]; Array.Copy(dirtyPages, 0, newDirtyPages, 0, dirtyPages.Length); dirtyPages = newDirtyPages; } dirtyPages[nDirtyPages] = pg; pg.writeQueueIndex = nDirtyPages++; } } }
internal static int getKeyStrOid(Page pg, int index) { return Bytes.unpack4(pg.data, firstKeyOffs + index * 8); }
internal void unfix(Page pg) { lock (this) { Debug.Assert(pg.accessCount > 0); if (--pg.accessCount == 0) { lru.link(pg); } } }
internal static int getKeyStrSize(Page pg, int index) { return Bytes.unpack2(pg.data, firstKeyOffs + index * 8 + 4); }
internal Page find(long addr, int state) { Debug.Assert((addr & (Page.pageSize - 1)) == 0); Page pg; int pageNo = (int)((ulong)addr >> Page.pageBits); int hashCode = pageNo % poolSize; lock (this) { int nCollisions = 0; for (pg = hashTable[hashCode]; pg != null; pg = pg.collisionChain) { if (pg.offs == addr) { if (pg.accessCount++ == 0) pg.unlink(); break; } nCollisions += 1; } if (pg == null) { pg = freePages; if (pg != null) freePages = (Page)pg.next; else if (autoExtended) { if (pageNo >= poolSize) { int newPoolSize = pageNo >= poolSize * 2 ? pageNo + 1 : poolSize * 2; Page[] newHashTable = new Page[newPoolSize]; Array.Copy(hashTable, 0, newHashTable, 0, hashTable.Length); hashTable = newHashTable; poolSize = newPoolSize; } pg = new Page(); hashCode = pageNo; } else { Debug.Assert(lru.prev != lru, "unfixed page available"); pg = (Page)lru.prev; pg.unlink(); lock (pg) { if ((pg.state & Page.psDirty) != 0) { pg.state = 0; file.Write(pg.offs, pg.data); if (!flushing) { dirtyPages[pg.writeQueueIndex] = dirtyPages[--nDirtyPages]; dirtyPages[pg.writeQueueIndex].writeQueueIndex = pg.writeQueueIndex; } } } int h = (int)(pg.offs >> Page.pageBits) % poolSize; Page curr = hashTable[h], prev = null; while (curr != pg) { prev = curr; curr = curr.collisionChain; } if (prev == null) hashTable[h] = pg.collisionChain; else prev.collisionChain = pg.collisionChain; } pg.accessCount = 1; pg.offs = addr; pg.state = Page.psRaw; pg.collisionChain = hashTable[hashCode]; hashTable[hashCode] = pg; } if ((pg.state & Page.psDirty) == 0 && (state & Page.psDirty) != 0) { Debug.Assert(!flushing); if (nDirtyPages >= dirtyPages.Length) { Page[] newDirtyPages = new Page[nDirtyPages * 2]; Array.Copy(dirtyPages, 0, newDirtyPages, 0, dirtyPages.Length); dirtyPages = newDirtyPages; } dirtyPages[nDirtyPages] = pg; pg.writeQueueIndex = nDirtyPages++; pg.state |= Page.psDirty; } if ((pg.state & Page.psRaw) != 0) { if (file.Read(pg.offs, pg.data) < Page.pageSize) Array.Clear(pg.data, 0, Page.pageSize); pg.state &= ~Page.psRaw; } } return pg; }
internal static void memcpy(Page dst_pg, int dst_idx, Page src_pg, int src_idx, int len, int itemSize) { Array.Copy(src_pg.data, firstKeyOffs + src_idx * itemSize, dst_pg.data, firstKeyOffs + dst_idx * itemSize, len * itemSize); }