readBytes on removed record will produce empty result instead of assertion,

better diagnostics (EA-82826)
This commit is contained in:
Maxim.Mossienko
2017-05-26 10:12:13 +02:00
parent 64be06bd19
commit d2353cfd3d
4 changed files with 22 additions and 11 deletions
@@ -103,7 +103,6 @@ public class CompactRecordsTable extends AbstractRecordsTable {
private static final int CAPACITY_MASK = 0x7FFF0000;
private static final int CAPACITY_SHIFT = 16;
private static final int SPECIAL_POSITIVE_VALUE_FOR_SPECIAL_NEGATIVE_SIZE = 0xFFFF;
private static final int SPECIAL_NEGATIVE_SIZE = -1;
@Override
public int getSize(int record) {
@@ -113,7 +112,7 @@ public class CompactRecordsTable extends AbstractRecordsTable {
return myStorage.getInt(getOffset(-currentValue, SIZE_OFFSET_IN_INDIRECT_RECORD));
}
int i = currentValue & SIZE_MASK;
if (i == SPECIAL_POSITIVE_VALUE_FOR_SPECIAL_NEGATIVE_SIZE) i = SPECIAL_NEGATIVE_SIZE;
if (i == SPECIAL_POSITIVE_VALUE_FOR_SPECIAL_NEGATIVE_SIZE) i = SPECIAL_NEGATIVE_SIZE_FOR_REMOVED_RECORD;
return i;
}
@@ -130,13 +129,13 @@ public class CompactRecordsTable extends AbstractRecordsTable {
}
// size to fit in normal record [-1 .. 0xFFFF)
if (size >= 0xFFFF || size < SPECIAL_NEGATIVE_SIZE || forceSplit) {
if (size >= 0xFFFF || size < SPECIAL_NEGATIVE_SIZE_FOR_REMOVED_RECORD || forceSplit) {
// introduce indirect record able to hold larger size range
extendSizeAndCapacityRecord(record, size, getCapacity(record));
return;
}
if (size == SPECIAL_NEGATIVE_SIZE) {
if (size == SPECIAL_NEGATIVE_SIZE_FOR_REMOVED_RECORD) {
size = SPECIAL_POSITIVE_VALUE_FOR_SPECIAL_NEGATIVE_SIZE;
}
@@ -232,7 +231,7 @@ public class CompactRecordsTable extends AbstractRecordsTable {
@Override
public boolean validId() {
assert hasNextId();
return getSize(nextId) != -1;
return isSizeOfLiveRecord(getSize(nextId));
}
};
}
@@ -52,6 +52,9 @@ public class CompactStorageTest extends StorageTestBase {
int logicalRecordCount = countLiveLogicalRecords();
assertEquals(recordCount / 2, logicalRecordCount);
int removedRecordId = recordsList.getQuick(0);
assertEquals("No content for reading removed record",0, myStorage.readStream(removedRecordId).available());
Disposer.dispose(myStorage); // compact is triggered
myStorage = createStorage(getFileName());
assertEquals(myStorage.getLiveRecordsCount(), physicalRecordCount / 2);
@@ -52,6 +52,7 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
private TIntArrayList myFreeRecordsList = null;
private boolean myIsDirty = false;
protected static final int SPECIAL_NEGATIVE_SIZE_FOR_REMOVED_RECORD = -1;
public AbstractRecordsTable(final File storageFilePath, final PagePool pool) throws IOException {
myStorage = new RandomAccessDataFile(storageFilePath, pool);
@@ -93,7 +94,7 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
}
else {
final int result = myFreeRecordsList.remove(myFreeRecordsList.size() - 1);
assert getSize(result) == -1;
assert isSizeOfRemovedRecord(getSize(result));
setSize(result, 0);
return result;
}
@@ -127,7 +128,7 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
@Override
public boolean validId() {
assert hasNextId();
return getSize(recordId) != -1;
return isSizeOfLiveRecord(getSize(recordId));
}
};
}
@@ -147,7 +148,7 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
private TIntArrayList scanForFreeRecords() throws IOException {
final TIntArrayList result = new TIntArrayList();
for (int i = 1; i <= getRecordsCount(); i++) {
if (getSize(i) == -1) {
if (isSizeOfRemovedRecord(getSize(i))) {
result.add(i);
}
}
@@ -194,7 +195,7 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
markDirty();
ensureFreeRecordsScanned();
doCleanRecord(record);
setSize(record, -1);
setSize(record, SPECIAL_NEGATIVE_SIZE_FOR_REMOVED_RECORD);
myFreeRecordsList.add(record);
}
@@ -248,4 +249,12 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
myStorage.putInt(HEADER_MAGIC_OFFSET, getSafelyClosedMagic());
}
}
protected static boolean isSizeOfRemovedRecord(int length) {
return length == SPECIAL_NEGATIVE_SIZE_FOR_REMOVED_RECORD;
}
protected static boolean isSizeOfLiveRecord(int length) {
return length != SPECIAL_NEGATIVE_SIZE_FOR_REMOVED_RECORD;
}
}
@@ -255,8 +255,8 @@ public abstract class AbstractStorage implements Disposable, Forceable {
protected byte[] readBytes(int record) throws IOException {
synchronized (myLock) {
final int length = myRecordsTable.getSize(record);
if (length == 0) return ArrayUtil.EMPTY_BYTE_ARRAY;
assert length > 0;
if (length == 0 || AbstractRecordsTable.isSizeOfRemovedRecord(length)) return ArrayUtil.EMPTY_BYTE_ARRAY;
assert length > 0:length;
final long address = myRecordsTable.getAddress(record);
byte[] result = new byte[length];