}
}
private BucketSearchResult splitBucket(List<OBonsaiBucketPointer> path, int keyIndex, K keyToInsert) throws IOException {
final OBonsaiBucketPointer bucketPointer = path.get(path.size() - 1);
OCacheEntry bucketEntry = diskCache.load(fileId, bucketPointer.getPageIndex(), false);
bucketEntry.acquireExclusiveLock();
try {
OSBTreeBonsaiBucket<K, V> bucketToSplit = new OSBTreeBonsaiBucket<K, V>(bucketEntry, bucketPointer.getPageOffset(),
keySerializer, valueSerializer, getTrackMode());
final boolean splitLeaf = bucketToSplit.isLeaf();
final int bucketSize = bucketToSplit.size();
int indexToSplit = bucketSize >>> 1;
final K separationKey = bucketToSplit.getKey(indexToSplit);
final List<OSBTreeBonsaiBucket.SBTreeEntry<K, V>> rightEntries = new ArrayList<OSBTreeBonsaiBucket.SBTreeEntry<K, V>>(
indexToSplit);
final int startRightIndex = splitLeaf ? indexToSplit : indexToSplit + 1;
for (int i = startRightIndex; i < bucketSize; i++)
rightEntries.add(bucketToSplit.getEntry(i));
if (!bucketPointer.equals(rootBucketPointer)) {
final AllocationResult allocationResult = allocateBucket();
OCacheEntry rightBucketEntry = allocationResult.getCacheEntry();
final OBonsaiBucketPointer rightBucketPointer = allocationResult.getPointer();
rightBucketEntry.acquireExclusiveLock();
try {
OSBTreeBonsaiBucket<K, V> newRightBucket = new OSBTreeBonsaiBucket<K, V>(rightBucketEntry,
rightBucketPointer.getPageOffset(), splitLeaf, keySerializer, valueSerializer, getTrackMode());
newRightBucket.addAll(rightEntries);
bucketToSplit.shrink(indexToSplit);
if (splitLeaf) {
OBonsaiBucketPointer rightSiblingBucketPointer = bucketToSplit.getRightSibling();
newRightBucket.setRightSibling(rightSiblingBucketPointer);
newRightBucket.setLeftSibling(bucketPointer);
bucketToSplit.setRightSibling(rightBucketPointer);
if (rightSiblingBucketPointer.isValid()) {
final OCacheEntry rightSiblingBucketEntry = diskCache.load(fileId, rightSiblingBucketPointer.getPageIndex(), false);
rightSiblingBucketEntry.acquireExclusiveLock();
OSBTreeBonsaiBucket<K, V> rightSiblingBucket = new OSBTreeBonsaiBucket<K, V>(rightSiblingBucketEntry,
rightSiblingBucketPointer.getPageOffset(), keySerializer, valueSerializer, getTrackMode());
try {
rightSiblingBucket.setLeftSibling(rightBucketPointer);
logPageChanges(rightSiblingBucket, fileId, rightSiblingBucketPointer.getPageIndex(), false);
} finally {
rightSiblingBucketEntry.releaseExclusiveLock();
diskCache.release(rightSiblingBucketEntry);
}
}
}
OBonsaiBucketPointer parentBucketPointer = path.get(path.size() - 2);
OCacheEntry parentCacheEntry = diskCache.load(fileId, parentBucketPointer.getPageIndex(), false);
parentCacheEntry.acquireExclusiveLock();
try {
OSBTreeBonsaiBucket<K, V> parentBucket = new OSBTreeBonsaiBucket<K, V>(parentCacheEntry,
parentBucketPointer.getPageOffset(), keySerializer, valueSerializer, getTrackMode());
OSBTreeBonsaiBucket.SBTreeEntry<K, V> parentEntry = new OSBTreeBonsaiBucket.SBTreeEntry<K, V>(bucketPointer,
rightBucketPointer, separationKey, null);
int insertionIndex = parentBucket.find(separationKey);
assert insertionIndex < 0;
insertionIndex = -insertionIndex - 1;
while (!parentBucket.addEntry(insertionIndex, parentEntry, true)) {
parentCacheEntry.releaseExclusiveLock();
diskCache.release(parentCacheEntry);
BucketSearchResult bucketSearchResult = splitBucket(path.subList(0, path.size() - 1), insertionIndex, separationKey);
parentBucketPointer = bucketSearchResult.getLastPathItem();
parentCacheEntry = diskCache.load(fileId, parentBucketPointer.getPageIndex(), false);
parentCacheEntry.acquireExclusiveLock();
insertionIndex = bucketSearchResult.itemIndex;
parentBucket = new OSBTreeBonsaiBucket<K, V>(parentCacheEntry, parentBucketPointer.getPageOffset(), keySerializer,
valueSerializer, getTrackMode());
}
logPageChanges(parentBucket, fileId, parentBucketPointer.getPageIndex(), false);
} finally {
parentCacheEntry.releaseExclusiveLock();
diskCache.release(parentCacheEntry);
}
logPageChanges(newRightBucket, fileId, rightBucketEntry.getPageIndex(), allocationResult.isNewPage());
} finally {
rightBucketEntry.releaseExclusiveLock();
diskCache.release(rightBucketEntry);
}
logPageChanges(bucketToSplit, fileId, bucketPointer.getPageIndex(), false);
ArrayList<OBonsaiBucketPointer> resultPath = new ArrayList<OBonsaiBucketPointer>(path.subList(0, path.size() - 1));
if (comparator.compare(keyToInsert, separationKey) < 0) {
resultPath.add(bucketPointer);
return new BucketSearchResult(keyIndex, resultPath);
}
resultPath.add(rightBucketPointer);
if (splitLeaf) {
return new BucketSearchResult(keyIndex - indexToSplit, resultPath);
}
return new BucketSearchResult(keyIndex - indexToSplit - 1, resultPath);
} else {
long treeSize = bucketToSplit.getTreeSize();
final List<OSBTreeBonsaiBucket.SBTreeEntry<K, V>> leftEntries = new ArrayList<OSBTreeBonsaiBucket.SBTreeEntry<K, V>>(
indexToSplit);
for (int i = 0; i < indexToSplit; i++)
leftEntries.add(bucketToSplit.getEntry(i));
final AllocationResult leftAllocationResult = allocateBucket();
OCacheEntry leftBucketEntry = leftAllocationResult.getCacheEntry();
OBonsaiBucketPointer leftBucketPointer = leftAllocationResult.getPointer();
final AllocationResult rightAllocationResult = allocateBucket();
OCacheEntry rightBucketEntry = rightAllocationResult.getCacheEntry();
OBonsaiBucketPointer rightBucketPointer = rightAllocationResult.getPointer();
leftBucketEntry.acquireExclusiveLock();
try {
OSBTreeBonsaiBucket<K, V> newLeftBucket = new OSBTreeBonsaiBucket<K, V>(leftBucketEntry,
leftBucketPointer.getPageOffset(), splitLeaf, keySerializer, valueSerializer, getTrackMode());
newLeftBucket.addAll(leftEntries);
if (splitLeaf)
newLeftBucket.setRightSibling(rightBucketPointer);
logPageChanges(newLeftBucket, fileId, leftBucketEntry.getPageIndex(), leftAllocationResult.isNewPage());
} finally {
leftBucketEntry.releaseExclusiveLock();
diskCache.release(leftBucketEntry);
}
rightBucketEntry.acquireExclusiveLock();
try {
OSBTreeBonsaiBucket<K, V> newRightBucket = new OSBTreeBonsaiBucket<K, V>(rightBucketEntry,
rightBucketPointer.getPageOffset(), splitLeaf, keySerializer, valueSerializer, getTrackMode());
newRightBucket.addAll(rightEntries);
if (splitLeaf)
newRightBucket.setLeftSibling(leftBucketPointer);
logPageChanges(newRightBucket, fileId, rightBucketEntry.getPageIndex(), rightAllocationResult.isNewPage());
rightBucketEntry.markDirty();
} finally {
rightBucketEntry.releaseExclusiveLock();
diskCache.release(rightBucketEntry);
}
bucketToSplit = new OSBTreeBonsaiBucket<K, V>(bucketEntry, bucketPointer.getPageOffset(), false, keySerializer,
valueSerializer, getTrackMode());