final long pageIndex = getPageIndex(bucketPointer);
final int fileLevel = getFileLevel(bucketPointer);
final V removed;
final OCacheEntry cacheEntry = loadPageEntry(pageIndex, fileLevel);
cacheEntry.acquireExclusiveLock();
try {
final OHashIndexBucket<K, V> bucket = new OHashIndexBucket<K, V>(cacheEntry, keySerializer, valueSerializer, keyTypes,
getTrackMode());
final int positionIndex = bucket.getIndex(hashCode, key);
if (positionIndex < 0) {
endAtomicOperation(false);
return null;
}
removed = bucket.deleteEntry(positionIndex).value;
sizeDiff--;
mergeBucketsAfterDeletion(nodePath, bucket);
cacheEntry.markDirty();
logPageChanges(bucket, cacheEntry.getFileId(), cacheEntry.getPageIndex(), false);
} finally {
cacheEntry.releaseExclusiveLock();
diskCache.release(cacheEntry);
}
if (nodePath.parent != null) {
final int hashMapSize = 1 << nodePath.nodeLocalDepth;
final boolean allMapsContainSameBucket = checkAllMapsContainSameBucket(directory.getNode(nodePath.nodeIndex), hashMapSize);
if (allMapsContainSameBucket)
mergeNodeToParent(nodePath);
}
changeSize(sizeDiff);
endAtomicOperation(false);
return removed;
} else {
if (diskCache.getFilledUpTo(nullBucketFileId) == 0)
return null;
V removed = null;
OCacheEntry cacheEntry = diskCache.load(nullBucketFileId, 0, false);
cacheEntry.acquireExclusiveLock();
try {
final ONullBucket<V> nullBucket = new ONullBucket<V>(cacheEntry, getTrackMode(), valueSerializer, false);
removed = nullBucket.getValue();
if (removed != null) {
nullBucket.removeValue();
sizeDiff--;
cacheEntry.markDirty();
logPageChanges(nullBucket, cacheEntry.getFileId(), cacheEntry.getPageIndex(), false);
}
} finally {
cacheEntry.releaseExclusiveLock();
diskCache.release(cacheEntry);
}
changeSize(sizeDiff);