package org.hsqldb.persist;
import java.util.concurrent.atomic.AtomicInteger;
import org.hsqldb.error.Error;
import org.hsqldb.error.ErrorCode;
import org.hsqldb.lib.ArrayUtil;
import org.hsqldb.lib.DoubleIntIndex;
import org.hsqldb.lib.IntIndex;
import org.hsqldb.lib.IntKeyHashMap;
import org.hsqldb.lib.Iterator;
import org.hsqldb.lib.OrderedIntHashSet;
public class DataSpaceManagerBlocks implements DataSpaceManager {
final DataFileCache cache;
final TableSpaceManagerBlocks defaultSpaceManager;
final TableSpaceManagerBlocks directorySpaceManager;
final IntKeyHashMap spaceManagerList;
final BlockObjectStore rootStore;
final BlockObjectStore directoryStore;
final BlockObjectStore bitMapStore;
IntArrayCachedObject rootBlock;
final AtomicInteger spaceIdSequence = new AtomicInteger(tableIdFirst);
final IntIndex emptySpaceList;
int released = 0;
public static final int dirBlockSize = 1024 * 2;
public static final int fileBlockItemCountLimit = 64 * 1024;
final int bitmapIntSize;
final int bitmapStorageSize;
final int fileBlockItemCount;
final int fileBlockSize;
final int dataFileScale;
BlockAccessor ba;
public DataSpaceManagerBlocks(DataFileCache dataFileCache) {
int bitmapStoreSizeTemp;
cache = dataFileCache;
dataFileScale = cache.getDataFileScale();
fileBlockSize = cache.database.logger.getDataFileSpaces() * 1024
* 1024;
fileBlockItemCount = fileBlockSize / dataFileScale;
bitmapIntSize = fileBlockItemCount / Integer.SIZE;
bitmapStoreSizeTemp = BitMapCachedObject.fileSizeFactor
* bitmapIntSize;
if (bitmapStoreSizeTemp < DataSpaceManager.fixedBlockSizeUnit) {
bitmapStoreSizeTemp = DataSpaceManager.fixedBlockSizeUnit;
}
bitmapStorageSize = bitmapStoreSizeTemp;
ba = new BlockAccessor();
spaceManagerList = new IntKeyHashMap();
emptySpaceList = new IntIndex(32, false);
directorySpaceManager = new TableSpaceManagerBlocks(this,
tableIdDirectory, fileBlockSize, 16, dataFileScale, 0);
defaultSpaceManager = new TableSpaceManagerBlocks(this,
tableIdDefault, fileBlockSize,
cache.database.logger.propMaxFreeBlocks, dataFileScale,
cache.database.logger.propMinReuse);
spaceManagerList.put(tableIdDirectory, directorySpaceManager);
spaceManagerList.put(tableIdDefault, defaultSpaceManager);
rootStore = getRootStore();
directoryStore = getDirectoryStore(false);
bitMapStore = getBitMapStore();
if (cache.spaceManagerPosition == 0) {
initialiseNewSpaceDirectory();
cache.spaceManagerPosition = rootBlock.getPos() * dataFileScale;
} else {
long pos = cache.spaceManagerPosition / dataFileScale;
rootBlock = (IntArrayCachedObject) rootStore.get(pos, true);
if (getBlockIndexLimit() == 0) {
throw Error.error(ErrorCode.FILE_IO_ERROR);
}
if (cache.isDataReadOnly()) {
return;
}
initialiseSpaceList();
initialiseTableSpace(directorySpaceManager);
initialiseTableSpace(defaultSpaceManager);
}
}
BlockObjectStore getRootStore() {
return new BlockObjectStore(cache, directorySpaceManager,
IntArrayCachedObject.class,
IntArrayCachedObject.fileSizeFactor
* dirBlockSize, dirBlockSize);
}
BlockObjectStore getDirectoryStore(boolean force240) {
return new BlockObjectStore(
cache, directorySpaceManager,
DirectoryBlockCachedObject.class,
DirectoryBlockCachedObject.fileSizeFactor * dirBlockSize,
dirBlockSize);
}
BlockObjectStore getBitMapStore() {
return new BlockObjectStore(cache, directorySpaceManager,
BitMapCachedObject.class,
bitmapStorageSize, bitmapIntSize);
}
private void initialiseNewSpaceDirectory() {
long currentSize = cache.getFileFreePos();
long totalBlocks = (currentSize / fileBlockSize) + 1;
long lastFreePosition = cache.enlargeFileSpace(totalBlocks
* fileBlockSize - currentSize);
defaultSpaceManager.initialiseFileBlock(null, lastFreePosition,
cache.getFileFreePos());
long defaultSpaceBlockCount = totalBlocks;
long directorySpaceBlockCount =
calculateDirectorySpaceBlocks(totalBlocks);
lastFreePosition = cache.enlargeFileSpace(directorySpaceBlockCount
* fileBlockSize);
directorySpaceManager.initialiseFileBlock(null, lastFreePosition,
cache.getFileFreePos());
IntArrayCachedObject root = new IntArrayCachedObject(dirBlockSize);
rootStore.add(root, true);
rootBlock = root;
createFileBlocksInDirectory((int) defaultSpaceBlockCount,
(int) directorySpaceBlockCount,
tableIdDirectory);
createFileBlocksInDirectory(0, (int) defaultSpaceBlockCount,
tableIdDefault);
}
private long calculateDirectorySpaceBlocks(long blockCount) {
long currentSize = calculateDirectorySpaceSize(blockCount);
long currentBlocks = currentSize / fileBlockSize + 1;
currentSize += calculateDirectorySpaceSize(currentBlocks);
currentBlocks = currentSize / fileBlockSize + 1;
return currentBlocks;
}
private long calculateDirectorySpaceSize(long blockCount) {
long blockLimit = ArrayUtil.getBinaryMultipleCeiling(blockCount + 1,
dirBlockSize);
long currentSize = IntArrayCachedObject.fileSizeFactor * blockLimit;
currentSize += DirectoryBlockCachedObject.fileSizeFactor * blockLimit;
currentSize += bitmapStorageSize * (blockCount + 1);
return currentSize;
}
private void ensureDirectorySpaceAvailable(int blockCount) {
int dirObjectSize = bitmapStorageSize * blockCount;
dirObjectSize += DirectoryBlockCachedObject.fileSizeFactor
* dirBlockSize;
boolean hasRoom = directorySpaceManager.hasFileRoom(dirObjectSize);
if (!hasRoom) {
long cacheFreePos;
int index = getBlockIndexLimit();
int dirBlockCount = dirObjectSize / fileBlockSize + 1;
long filePosition = cache.enlargeFileSpace((long) dirBlockCount
* fileBlockSize);
directorySpaceManager.addFileBlock(filePosition,
filePosition
+ (long) dirBlockCount
* fileBlockSize);
createFileBlocksInDirectory(index, dirBlockCount,
tableIdDirectory);
cacheFreePos = cache.getFileFreePos();
index = getBlockIndexLimit();
if ((long) index * fileBlockSize != cacheFreePos) {
cache.logSevereEvent(
"space manager end file pos different from data file: "
+ (index * fileBlockSize) + ", " + cacheFreePos, null);
}
}
}
public long getFileBlocks(int tableId, int blockCount) {
cache.writeLock.lock();
try {
long index = getExistingBlockIndex(tableId, blockCount);
if (index > 0) {
return index * fileBlockSize;
} else {
return getNewFileBlocks(tableId, blockCount);
}
} finally {
cache.writeLock.unlock();
}
}
private long getNewFileBlocks(int tableId, int blockCount) {
ensureDirectorySpaceAvailable(blockCount);
return getNewFileBlocksNoCheck(tableId, blockCount);
}
private long getNewFileBlocksNoCheck(int tableId, int blockCount) {
long index = getBlockIndexLimit();
long filePosition = index * fileBlockSize;
long delta = filePosition + ((long) blockCount * fileBlockSize)
- cache.getFileFreePos();
if (delta > 0) {
cache.enlargeFileSpace(delta);
}
createFileBlocksInDirectory((int) index, blockCount, tableId);
return filePosition;
}
private void createFileBlocksInDirectory(int fileBlockIndex,
int blockCount, int tableId) {
for (int i = 0; i < blockCount; i++) {
createFileBlockInDirectory(fileBlockIndex + i, tableId);
}
}
private void createFileBlockInDirectory(int fileBlockIndex, int tableId) {
BitMapCachedObject bitMap = new BitMapCachedObject(bitmapIntSize);
bitMapStore.add(bitMap, false);
int bitmapBlockPos = (int) (bitMap.getPos() * dataFileScale
/ DataSpaceManager.fixedBlockSizeUnit);
int blockOffset = fileBlockIndex % dirBlockSize;
DirectoryBlockCachedObject directory = getDirectory(fileBlockIndex,
true);
if (directory == null) {
createDirectory(fileBlockIndex);
directory = getDirectory(fileBlockIndex, true);
}
directory.setTableId(blockOffset, tableId);
directory.setBitmapAddress(blockOffset, bitmapBlockPos);
directory.keepInMemory(false);
}
private DirectoryBlockCachedObject getDirectory(int fileBlockIndex,
boolean keep) {
int indexInRoot = fileBlockIndex / dirBlockSize;
return getDirectoryByIndex(indexInRoot, keep);
}
private DirectoryBlockCachedObject getDirectoryByIndex(int indexInRoot,
boolean keep) {
long position = rootBlock.getValue(indexInRoot);
DirectoryBlockCachedObject directory;
if (position == 0) {
return null;
}
position *= (DataSpaceManager.fixedBlockSizeUnit / dataFileScale);
directory = (DirectoryBlockCachedObject) directoryStore.get(position,
keep);
return directory;
}
private void createDirectory(int fileBlockIndex) {
DirectoryBlockCachedObject directory;
directory = new DirectoryBlockCachedObject(dirBlockSize);
directoryStore.add(directory, false);
int indexInRoot = fileBlockIndex / dirBlockSize;
int blockPosition = (int) (directory.getPos() * dataFileScale
/ DataSpaceManager.fixedBlockSizeUnit);
rootBlock.setValue(indexInRoot, blockPosition);
}
private int getBlockIndexLimit() {
int indexInRoot = rootBlock.getNonZeroSize();
if (indexInRoot == 0) {
return 0;
}
indexInRoot--;
int directoryBlockOffset = getDirectoryIndexLimit(indexInRoot);
return indexInRoot * dirBlockSize + directoryBlockOffset;
}
private int getDirectoryIndexLimit(int indexInRoot) {
DirectoryBlockCachedObject directory = getDirectoryByIndex(indexInRoot,
false);
int[] bitmapArray = directory.getBitmapAddressArray();
int index = 0;
for (; index < bitmapArray.length; index++) {
if (bitmapArray[index] == 0) {
break;
}
}
return index;
}
private void initialiseSpaceList() {
int maxId = tableIdDefault;
OrderedIntHashSet list = new OrderedIntHashSet();
ba.initialise(false);
try {
for (;;) {
boolean result = ba.nextBlock();
if (!result) {
break;
}
int currentId = ba.getTableId();
if (currentId > maxId) {
maxId = currentId;
}
if (currentId == tableIdEmpty) {
int freeItems = ba.getFreeSpaceValue();
int freeItemsEnd = ba.getFreeBlockValue();
if (freeItems == 0 && freeItemsEnd == 0) {
emptySpaceList.addUnique(ba.currentBlockIndex);
} else {
list.add(ba.currentBlockIndex);
}
}
}
} finally {
ba.reset();
}
spaceIdSequence.set((maxId + 2) & -2);
if (list.size() > 0) {
setAsideBlocks(list);
String s =
"space manager error - recovered (freeItems in empty blocks) : ("
+ list.size() + ")";
cache.logSevereEvent(s, null);
}
}
private int getExistingBlockIndex(int tableId, int blockCount) {
int blockIndex = emptySpaceList.removeFirstConsecutiveKeys(blockCount,
-1);
if (blockIndex > 0) {
setDirectoryBlocksAsTable(tableId, blockIndex, blockCount);
}
return blockIndex;
}
private void setDirectoryBlocksAsTable(int tableId, int blockIndex,
int blockCount) {
int directoryIndex = -1;
DirectoryBlockCachedObject directory = null;
for (int i = blockIndex; i < blockIndex + blockCount; i++) {
if (directoryIndex != i / dirBlockSize) {
if (directory != null) {
directory.keepInMemory(false);
}
directory = getDirectory(i, true);
directoryIndex = i / dirBlockSize;
}
int offset = i % dirBlockSize;
directory.setTableId(offset, tableId);
}
directory.keepInMemory(false);
}
public TableSpaceManager getDefaultTableSpace() {
return defaultSpaceManager;
}
public TableSpaceManager getTableSpace(int spaceId) {
if (spaceId == DataSpaceManager.tableIdDefault) {
return defaultSpaceManager;
}
if (spaceId >= spaceIdSequence.get()) {
spaceIdSequence.set((spaceId + 2) & -2);
}
cache.writeLock.lock();
try {
TableSpaceManagerBlocks manager =
(TableSpaceManagerBlocks) spaceManagerList.get(spaceId);
if (manager == null) {
int minReuse = cache.database.logger.propMinReuse;
manager = new TableSpaceManagerBlocks(
this, spaceId, fileBlockSize,
cache.database.logger.propMaxFreeBlocks, dataFileScale,
minReuse);
spaceManagerList.put(spaceId, manager);
}
return manager;
} finally {
cache.writeLock.unlock();
}
}
public int getNewTableSpaceID() {
return spaceIdSequence.getAndAdd(2);
}
public void freeTableSpace(int spaceId) {
if (spaceId == tableIdDefault || spaceId == tableIdDirectory) {
return;
}
cache.writeLock.lock();
try {
TableSpaceManager tableSpace =
(TableSpaceManager) spaceManagerList.get(spaceId);
if (tableSpace != null) {
tableSpace.reset();
}
IntIndex list = new IntIndex(16, false);
ba.initialise(true);
try {
while (ba.nextBlockForTable(spaceId)) {
list.addUnsorted(ba.currentBlockIndex);
ba.setTable(tableIdEmpty);
emptySpaceList.addUnique(ba.currentBlockIndex);
}
} finally {
ba.reset();
}
cache.releaseRange(list, fileBlockItemCount);
} finally {
cache.writeLock.unlock();
}
}
public void freeTableSpace(int spaceId, DoubleIntIndex spaceList,
long offset, long limit, boolean full) {
if (spaceList.size() == 0 && offset == limit) {
return;
}
spaceList.compactLookupAsIntervals();
if (!full) {
int available = spaceList.capacity() - spaceList.size();
if (available > spaceList.capacity() / 4) {
spaceList.setValuesSearchTarget();
spaceList.sort();
return;
}
}
cache.writeLock.lock();
try {
ba.initialise(true);
try {
int[] keys = spaceList.getKeys();
int[] values = spaceList.getValues();
for (int i = 0; i < spaceList.size(); i++) {
int position = keys[i];
int units = values[i];
freeTableSpacePart(position, units);
}
long position = offset / dataFileScale;
int units = (int) ((limit - offset) / dataFileScale);
freeTableSpacePart(position, units);
} finally {
ba.reset();
}
} finally {
cache.writeLock.unlock();
}
spaceList.clear();
spaceList.setValuesSearchTarget();
}
private void freeTableSpacePart(long position, int units) {
for (; units > 0; ) {
int blockIndex = (int) (position / fileBlockItemCount);
int offset = (int) (position % fileBlockItemCount);
int currentUnits = fileBlockItemCount - offset;
if (currentUnits > units) {
currentUnits = units;
}
boolean result = ba.moveToBlock(blockIndex);
if (result) {
int setCount = ba.setRange(offset, currentUnits);
if (setCount != currentUnits) {
ba.unsetRange(offset, currentUnits);
String s =
"space manager error - recovered (block, offset, units) : ("
+ blockIndex + "," + offset + "," + units + ")";
cache.logSevereEvent(s, null);
}
} else {
String s =
"space manager error - recovered (block, offset, units) : ("
+ blockIndex + "," + offset + "," + units + ")";
cache.logSevereEvent(s, null);
}
units -= currentUnits;
position += currentUnits;
}
}
int findTableSpace(long position) {
int blockIndex = (int) (position / fileBlockItemCount);
cache.writeLock.lock();
try {
ba.initialise(false);
try {
boolean result = ba.moveToBlock(blockIndex);
if (!result) {
return -1;
}
int id = ba.getTableId();
return id;
} finally {
ba.reset();
}
} finally {
cache.writeLock.unlock();
}
}
void setAsideBlocks(OrderedIntHashSet blocks) {
cache.writeLock.lock();
try {
ba.initialise(true);
try {
for (int i = 0; i < blocks.size(); i++) {
int block = blocks.get(i);
boolean result = ba.moveToBlock(block);
if (result) {
ba.setTable(DataSpaceManager.tableIdSetAside);
}
}
} finally {
ba.reset();
}
} finally {
cache.writeLock.unlock();
}
}
public long getLostBlocksSize() {
long fragment = 0;
cache.writeLock.lock();
try {
ba.initialise(false);
try {
for (;;) {
boolean result = ba.nextBlock();
if (!result) {
break;
}
if (ba.getTableId() == tableIdDirectory) {
continue;
}
fragment += ba.getFreeSpaceValue() * dataFileScale;
if (ba.getTableId() == tableIdEmpty) {
fragment += fileBlockSize;
}
}
} finally {
ba.reset();
}
} finally {
cache.writeLock.unlock();
}
return fragment;
}
public int getFileBlockSize() {
return fileBlockSize;
}
public boolean isModified() {
return true;
}
public void initialiseSpaces() {
cache.writeLock.lock();
try {
Iterator it = spaceManagerList.values().iterator();
while (it.hasNext()) {
TableSpaceManagerBlocks tableSpace =
(TableSpaceManagerBlocks) it.next();
if (tableSpace.getSpaceID() == DataSpaceManager
.tableIdDirectory || tableSpace
.getFileBlockIndex() != -1) {
initialiseTableSpace(tableSpace);
}
}
} finally {
cache.writeLock.unlock();
}
}
public void reset() {
cache.writeLock.lock();
try {
Iterator it = spaceManagerList.values().iterator();
while (it.hasNext()) {
TableSpaceManagerBlocks tableSpace =
(TableSpaceManagerBlocks) it.next();
tableSpace.reset();
}
} finally {
cache.writeLock.unlock();
}
}
public boolean isMultiSpace() {
return true;
}
public int getFileBlockItemCount() {
return fileBlockItemCount;
}
public DirectoryBlockCachedObject[] getDirectoryList() {
int count = 0;
DirectoryBlockCachedObject[] directoryList;
int[] rootArray = rootBlock.getIntArray();
while (rootArray[count] != 0) {
count++;
}
directoryList = new DirectoryBlockCachedObject[count];
for (int i = 0; i < directoryList.length; i++) {
directoryList[i] = getDirectory(i * dirBlockSize, false);
}
return directoryList;
}
DoubleIntIndex checkDirectorySpaces() {
DirectoryBlockCachedObject[] directoryList = getDirectoryList();
DoubleIntIndex offspaceBitmaps = new DoubleIntIndex(8, false);
offspaceBitmaps.setKeysSearchTarget();
DoubleIntIndex positionBitmaps = new DoubleIntIndex(8, false);
positionBitmaps.setKeysSearchTarget();
for (int i = 0; i < directoryList.length; i++) {
DirectoryBlockCachedObject dir = directoryList[i];
long position = dir.getPos();
int spaceId = findTableSpace(position);
int blockIndex = i;
int blockPos = rootBlock.getValue(blockIndex);
boolean result;
int count = dir.getStorageSize()
/ DataSpaceManager.fixedBlockSizeUnit;
for (int j = 0; j < count; j++) {
result = positionBitmaps.addUnique(blockPos, blockIndex);
}
int[] bitMapAddress = dir.getBitmapAddressArray();
for (int j = 0; j < bitMapAddress.length; j++) {
blockPos = dir.getBitmapAddress(j);
if (blockPos == 0) {
break;
}
position = blockPos
* (DataSpaceManager.fixedBlockSizeUnit
/ dataFileScale);
spaceId = findTableSpace(position);
blockIndex = i * dirBlockSize + j;
if (spaceId != DataSpaceManager.tableIdDirectory) {
offspaceBitmaps.add(blockIndex, spaceId);
} else {
result = positionBitmaps.addUnique(blockPos, blockIndex);
if (!result) {
offspaceBitmaps.add(blockIndex, spaceId);
int offset =
positionBitmaps.findFirstEqualKeyIndex(blockPos);
blockIndex = positionBitmaps.getValue(offset);
offspaceBitmaps.add(blockIndex, spaceId);
}
}
}
}
return offspaceBitmaps;
}
DoubleIntIndex checkDirectoryBitmaps(DirectoryBlockCachedObject mismatch) {
DirectoryBlockCachedObject[] directoryList = getDirectoryList();
DoubleIntIndex offspaceBitmaps = new DoubleIntIndex(8, false);
offspaceBitmaps.setKeysSearchTarget();
int mismatchCount = 0;
for (int i = 0; i < directoryList.length; i++) {
DirectoryBlockCachedObject dir = directoryList[i];
int[] bitMapAddress = dir.getBitmapAddressArray();
for (int j = 0; j < bitMapAddress.length; j++) {
int blockPos = dir.getBitmapAddress(j);
if (blockPos == 0) {
break;
}
long position = blockPos
* (DataSpaceManager.fixedBlockSizeUnit
/ dataFileScale);
int spaceId = findTableSpace(position);
int blockIndex = i * dirBlockSize + j;
BitMapCachedObject currentBitMap =
(BitMapCachedObject) bitMapStore.get(position, false);
spaceId = dir.getTableId(j);
int freeUnits = currentBitMap.bitMap.countSetBits();
int freeBlockUnits = currentBitMap.bitMap.countSetBitsEnd();
if (dir.getFreeSpace(j) != freeUnits
|| dir.getFreeBlock(j) != freeBlockUnits) {
offspaceBitmaps.add(blockIndex, spaceId);
mismatch.setTableId(mismatchCount, spaceId);
mismatch.setFreeSpace(mismatchCount, (char) freeUnits);
mismatch.setFreeBlock(mismatchCount,
(char) freeBlockUnits);
mismatchCount++;
if (mismatchCount == mismatch.getTableIdArray().length) {
break;
}
}
}
}
return offspaceBitmaps;
}
private void initialiseTableSpace(TableSpaceManagerBlocks tableSpace) {
int spaceId = tableSpace.getSpaceID();
int blockIndex = -1;
int lastBlockIndex = tableSpace.getFileBlockIndex();
if (lastBlockIndex >= 0) {
if (hasFreeSpace(spaceId, lastBlockIndex)) {
blockIndex = lastBlockIndex;
}
}
if (blockIndex < 0) {
blockIndex = findLargestFreeSpace(spaceId);
}
if (blockIndex < 0) {
return;
}
initialiseTableSpace(tableSpace, blockIndex);
}
private boolean hasFreeSpace(int spaceId, int blockIndex) {
ba.initialise(false);
try {
boolean result = ba.moveToBlock(blockIndex);
if (result) {
if (ba.getTableId() == spaceId) {
if (ba.getFreeBlockValue() > 0) {
return true;
}
}
}
return false;
} finally {
ba.reset();
}
}
private int findLargestFreeSpace(int spaceId) {
int maxFree = 0;
int blockIndex = -1;
ba.initialise(false);
try {
for (; ba.nextBlockForTable(spaceId); ) {
int currentFree = ba.getFreeBlockValue();
if (currentFree > maxFree) {
blockIndex = ba.currentBlockIndex;
maxFree = currentFree;
}
}
return blockIndex;
} finally {
ba.reset();
}
}
private void initialiseTableSpace(TableSpaceManagerBlocks tableSpace,
int blockIndex) {
ba.initialise(true);
try {
ba.moveToBlock(blockIndex);
int freeItems = ba.getFreeBlockValue();
long blockPos = (long) blockIndex * fileBlockSize;
int unsetCount = ba.unsetRange(fileBlockItemCount - freeItems,
freeItems);
if (unsetCount == freeItems) {
tableSpace.initialiseFileBlock(
null,
blockPos + (fileBlockSize - freeItems * dataFileScale),
blockPos + fileBlockSize);
} else {
cache.logSevereEvent("space manager error - recovered", null);
}
} finally {
ba.reset();
}
}
private class BlockAccessor {
boolean currentKeep;
int currentBlockIndex = -1;
int currentDirIndex = -1;
int currentBlockOffset = -1;
DirectoryBlockCachedObject currentDir = null;
BitMapCachedObject currentBitMap = null;
void initialise(boolean forUpdate) {
currentKeep = forUpdate;
}
boolean nextBlock() {
boolean result = moveToBlock(currentBlockIndex + 1);
return result;
}
boolean nextBlockForTable(int tableId) {
for (;;) {
boolean result = moveToBlock(currentBlockIndex + 1);
if (!result) {
return false;
}
if (getTableId() == tableId) {
return true;
}
}
}
boolean moveToBlock(int fileBlockIndex) {
if (currentBlockIndex != fileBlockIndex) {
endBlockUpdate();
currentBitMap = null;
if (currentDirIndex != fileBlockIndex / dirBlockSize) {
reset();
currentDirIndex = fileBlockIndex / dirBlockSize;
currentDir = getDirectory(fileBlockIndex, currentKeep);
}
if (currentDir == null) {
reset();
return false;
}
currentBlockIndex = fileBlockIndex;
currentBlockOffset = fileBlockIndex % dirBlockSize;
long position =
currentDir.getBitmapAddress(currentBlockOffset);
if (position == 0) {
reset();
return false;
}
if (currentKeep) {
position *= (DataSpaceManager.fixedBlockSizeUnit
/ dataFileScale);
currentBitMap =
(BitMapCachedObject) bitMapStore.get(position, true);
}
}
return true;
}
int setRange(int offset, int currentUnits) {
currentBitMap.setChanged(true);
return currentBitMap.bitMap.setRange(offset, currentUnits);
}
int unsetRange(int offset, int currentUnits) {
currentBitMap.setChanged(true);
return currentBitMap.bitMap.unsetRange(offset, currentUnits);
}
void reset() {
endBlockUpdate();
if (currentDir != null) {
if (currentKeep) {
currentDir.keepInMemory(false);
}
}
currentBlockIndex = -1;
currentDirIndex = -1;
currentBlockOffset = -1;
currentDir = null;
currentBitMap = null;
}
private void endBlockUpdate() {
if (currentBitMap == null) {
return;
}
if (!currentBitMap.hasChanged()) {
currentBitMap.keepInMemory(false);
return;
}
int freeUnits = currentBitMap.bitMap.countSetBits();
int freeBlockUnits = currentBitMap.bitMap.countSetBitsEnd();
if (freeUnits == fileBlockItemCount) {
int currentId =
currentDir.getTableIdArray()[currentBlockOffset];
if (currentId != DataSpaceManager.tableIdSetAside) {
setTable(DataSpaceManager.tableIdEmpty);
emptySpaceList.addUnique(currentBlockIndex);
released++;
}
currentBitMap.keepInMemory(false);
return;
}
currentBitMap.keepInMemory(false);
currentDir.setFreeSpace(currentBlockOffset, (char) freeUnits);
currentDir.setFreeBlock(currentBlockOffset, (char) freeBlockUnits);
}
void setTable(int tableId) {
currentDir.setTableId(currentBlockOffset, tableId);
currentDir.setFreeSpace(currentBlockOffset, (char) 0);
currentDir.setFreeBlock(currentBlockOffset, (char) 0);
currentBitMap.bitMap.reset();
currentBitMap.setChanged(true);
}
int getTableId() {
return currentDir.getTableId(currentBlockOffset);
}
char getFreeSpaceValue() {
return currentDir.getFreeSpace(currentBlockOffset);
}
char getFreeBlockValue() {
return currentDir.getFreeBlock(currentBlockOffset);
}
}
}