Skip to content

Commit 816d63f

Browse files
committed
fixup! WIP Refactoring and cleanup of BTree storage classes
1 parent cd92462 commit 816d63f

File tree

4 files changed

+238
-111
lines changed

4 files changed

+238
-111
lines changed

exist-core/src/main/java/org/exist/storage/btree/AbstractPagedFileHeader.java

Lines changed: 92 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -95,60 +95,70 @@
9595
*/
9696
public abstract class AbstractPagedFileHeader implements PagedFileHeader {
9797
//<editor-fold desc="Description of the file header format">
98-
private static final int LENGTH_VERSION_ID = 2; //sizeof short
99-
private static final int LENGTH_HEADER_SIZE = 2; //sizeof short
100-
private static final int LENGTH_PAGE_COUNT = 8; //sizeof long
101-
private static final int LENGTH_PAGE_SIZE = 4; //sizeof int
102-
private static final int LENGTH_TOTAL_COUNT = 8; //sizeof long
103-
private static final int LENGTH_FIRST_FREE_PAGE = 8; //sizeof long
104-
private static final int LENGTH_LAST_FREE_PAGE = 8; //sizeof long
105-
private static final int LENGTH_PAGE_HEADER_SIZE = 1; //sizeof byte
106-
private static final int LENGTH_MAX_KEY_SIZE = 2; //sizeof short
107-
private static final int LENGTH_RECORD_COUNT = 8; //sizeof long
108-
109-
private static final int OFFSET_VERSION_ID = 0;
110-
private static final int OFFSET_HEADER_SIZE = OFFSET_VERSION_ID + LENGTH_VERSION_ID; //2
111-
private static final int OFFSET_PAGE_SIZE = OFFSET_HEADER_SIZE + LENGTH_HEADER_SIZE; //4
112-
private static final int OFFSET_PAGE_COUNT = OFFSET_PAGE_SIZE + LENGTH_PAGE_SIZE; //8
113-
private static final int OFFSET_TOTAL_COUNT = OFFSET_PAGE_COUNT + LENGTH_PAGE_COUNT; //16
114-
private static final int OFFSET_FIRST_FREE_PAGE = OFFSET_TOTAL_COUNT + LENGTH_TOTAL_COUNT; //24
115-
private static final int OFFSET_LAST_FREE_PAGE = OFFSET_FIRST_FREE_PAGE + LENGTH_FIRST_FREE_PAGE; //32
116-
private static final int OFFSET_PAGE_HEADER_SIZE = OFFSET_LAST_FREE_PAGE + LENGTH_LAST_FREE_PAGE; //40
117-
private static final int OFFSET_MAX_KEY_SIZE = OFFSET_PAGE_HEADER_SIZE + LENGTH_PAGE_HEADER_SIZE; //41
118-
private static final int OFFSET_RECORD_COUNT = OFFSET_MAX_KEY_SIZE + LENGTH_MAX_KEY_SIZE; //43
119-
private static final int OFFSET_REMAINDER = OFFSET_RECORD_COUNT + LENGTH_RECORD_COUNT; //51
98+
private static final int LENGTH_VERSION_ID = 2; // sizeof(short)
99+
private static final int LENGTH_HEADER_SIZE = 2; // sizeof(short)
100+
private static final int LENGTH_PAGE_COUNT = 8; // sizeof(long)
101+
private static final int LENGTH_PAGE_SIZE = 4; // sizeof(int)
102+
private static final int LENGTH_TOTAL_COUNT = 8; // sizeof(long)
103+
private static final int LENGTH_FIRST_FREE_PAGE = 8; // sizeof(long)
104+
private static final int LENGTH_LAST_FREE_PAGE = 8; // sizeof(long)
105+
private static final int LENGTH_PAGE_HEADER_SIZE = 1; // sizeof(byte)
106+
private static final int LENGTH_MAX_KEY_SIZE = 2; // sizeof(short)
107+
protected static final int LENGTH_RECORD_COUNT = 8; // sizeof(long)
108+
109+
private static final int OFFSET_VERSION_ID = 0; // 0
110+
private static final int OFFSET_HEADER_SIZE = OFFSET_VERSION_ID + LENGTH_VERSION_ID; // 2
111+
private static final int OFFSET_PAGE_SIZE = OFFSET_HEADER_SIZE + LENGTH_HEADER_SIZE; // 4
112+
private static final int OFFSET_PAGE_COUNT = OFFSET_PAGE_SIZE + LENGTH_PAGE_SIZE; // 8
113+
private static final int OFFSET_TOTAL_COUNT = OFFSET_PAGE_COUNT + LENGTH_PAGE_COUNT; // 16
114+
private static final int OFFSET_FIRST_FREE_PAGE = OFFSET_TOTAL_COUNT + LENGTH_TOTAL_COUNT; // 24
115+
private static final int OFFSET_LAST_FREE_PAGE = OFFSET_FIRST_FREE_PAGE + LENGTH_FIRST_FREE_PAGE; // 32
116+
private static final int OFFSET_PAGE_HEADER_SIZE = OFFSET_LAST_FREE_PAGE + LENGTH_LAST_FREE_PAGE; // 40
117+
private static final int OFFSET_MAX_KEY_SIZE = OFFSET_PAGE_HEADER_SIZE + LENGTH_PAGE_HEADER_SIZE; // 41
118+
protected static final int OFFSET_RECORD_COUNT = OFFSET_MAX_KEY_SIZE + LENGTH_MAX_KEY_SIZE; // 43
120119
//</editor-fold>
121120

122121
private final static byte DEFAULT_PAGE_HEADER_SIZE = 64;
123122
private final static short DEFAULT_MAX_KEY_SIZE = 256;
124123

125124
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
126125

127-
private short version; // TODO(AR) try and make final?
128-
private short headerSize; // TODO(AR) try and make final?
129-
private int pageSize; // TODO(AR) try and make final?
126+
//<editor-fold desc="Immutable state">
127+
private final short version;
128+
private final short headerSize;
129+
private final int pageSize;
130+
private final byte pageHeaderSize;
131+
private final short maxKeySize;
132+
private final int workSize;
133+
134+
/**
135+
* This is here so that we can allocate once and reuse multiple times in {@link #write(byte[])}.
136+
*/
137+
private final byte[] headerBuf;
138+
// </editor-fold>
139+
140+
//<editor-fold desc="Mutable state">
130141
private long totalCount;
131-
private long firstFreePage = Page.NO_PAGE;
132-
private long lastFreePage = Page.NO_PAGE;
133-
private byte pageHeaderSize = DEFAULT_PAGE_HEADER_SIZE; // TODO(AR) try and make final?
134-
private short maxKeySize = DEFAULT_MAX_KEY_SIZE; // TODO(AR) try and make final?
135-
136-
private final byte[] buf;
137-
private int workSize; // TODO(AR) try and make final, i.e. calculate once and then we don't need to re-calc ?
138-
private boolean dirty = false;
139-
140-
public AbstractPagedFileHeader(final short fileVersion, final long pageCount, final int pageSize) {
141-
this.version = fileVersion;
142-
this.headerSize = (short) pageSize;
142+
private long firstFreePage;
143+
private long lastFreePage;
144+
private boolean dirty;
145+
//</editor-fold>
146+
147+
protected AbstractPagedFileHeader(final short version, final short headerSize, final int pageSize, final byte pageHeaderSize, final short maxKeySize, final long firstFreePage, final long lastFreePage, final long totalCount) {
148+
this.version = version;
149+
this.headerSize = headerSize;
143150
this.pageSize = pageSize;
144-
this.totalCount = pageCount;
145-
this.buf = new byte[this.headerSize];
146-
this.workSize = calculateWorkSize();
151+
this.pageHeaderSize = pageHeaderSize;
152+
this.maxKeySize = maxKeySize;
153+
this.firstFreePage = firstFreePage;
154+
this.lastFreePage = lastFreePage;
155+
this.totalCount = totalCount;
156+
this.workSize = this.pageSize - this.pageHeaderSize;
157+
this.headerBuf = new byte[headerSize];
147158
}
148159

149-
// TODO(AR) remove this and try and inline it
150-
private int calculateWorkSize() {
151-
return this.pageSize - this.pageHeaderSize;
160+
protected AbstractPagedFileHeader(final short version, final long pageCount, final int pageSize) {
161+
this(version, (short) pageSize, pageSize, DEFAULT_PAGE_HEADER_SIZE, DEFAULT_MAX_KEY_SIZE, Page.NO_PAGE, Page.NO_PAGE, pageCount);
152162
}
153163

154164
/**
@@ -280,28 +290,21 @@ public void setDirty(final boolean dirty) {
280290
this.dirty = dirty;
281291
}
282292

283-
public void read(final RandomAccessFile raf) throws IOException {
284-
raf.seek(0);
285-
raf.read(this.buf);
286-
read(this.buf);
287-
this.workSize = calculateWorkSize();
288-
this.dirty = false;
289-
}
290-
291-
protected int read(final byte[] buf) throws IOException {
292-
this.version = ByteConversion.byteToShort(buf, OFFSET_VERSION_ID);
293-
this.headerSize = ByteConversion.byteToShort(buf, OFFSET_HEADER_SIZE);
294-
this.pageSize = ByteConversion.byteToInt(buf, OFFSET_PAGE_SIZE);
293+
protected static AbstractPagedFileHeaderData readAbstractPagedFileHeaderData(final byte[] headerBuf) {
294+
final short version = ByteConversion.byteToShort(headerBuf, OFFSET_VERSION_ID);
295+
final short headerSize = ByteConversion.byteToShort(headerBuf, OFFSET_HEADER_SIZE);
296+
final int pageSize = ByteConversion.byteToInt(headerBuf, OFFSET_PAGE_SIZE);
295297
// NOTE(AR) pageCount no longer seems to be needed
296-
// this.pageCount = ByteConversion.byteToLong(buf, OFFSET_PAGE_COUNT);
297-
this.totalCount = ByteConversion.byteToLong(buf, OFFSET_TOTAL_COUNT);
298-
this.firstFreePage = ByteConversion.byteToLong(buf, OFFSET_FIRST_FREE_PAGE);
299-
this.lastFreePage = ByteConversion.byteToLong(buf, OFFSET_LAST_FREE_PAGE);
300-
this.pageHeaderSize = buf[OFFSET_PAGE_HEADER_SIZE];
301-
this.maxKeySize = ByteConversion.byteToShort(buf, OFFSET_MAX_KEY_SIZE);
298+
// final long pageCount = ByteConversion.byteToLong(buf, OFFSET_PAGE_COUNT);
299+
final long totalCount = ByteConversion.byteToLong(headerBuf, OFFSET_TOTAL_COUNT);
300+
final long firstFreePage = ByteConversion.byteToLong(headerBuf, OFFSET_FIRST_FREE_PAGE);
301+
final long lastFreePage = ByteConversion.byteToLong(headerBuf, OFFSET_LAST_FREE_PAGE);
302+
final byte pageHeaderSize = headerBuf[OFFSET_PAGE_HEADER_SIZE];
303+
final short maxKeySize = ByteConversion.byteToShort(headerBuf, OFFSET_MAX_KEY_SIZE);
302304
// NOTE(AR) recordCount no longer seems to be needed
303-
// this.recordCount = ByteConversion.byteToLong(buf, OFFSET_RECORD_COUNT);
304-
return OFFSET_REMAINDER;
305+
// final long recordCount = ByteConversion.byteToLong(buf, OFFSET_RECORD_COUNT);
306+
307+
return new AbstractPagedFileHeaderData(version, headerSize, pageSize, totalCount, firstFreePage, lastFreePage, pageHeaderSize, maxKeySize);
305308
}
306309

307310
protected int write(final byte[] buf) throws IOException {
@@ -317,13 +320,13 @@ protected int write(final byte[] buf) throws IOException {
317320
ByteConversion.shortToByte(this.maxKeySize, buf, OFFSET_MAX_KEY_SIZE);
318321
// NOTE(AR) recordCount no longer seems to be needed
319322
// ByteConversion.longToByte(this.recordCount, buf, OFFSET_RECORD_COUNT);
320-
return OFFSET_REMAINDER;
323+
return OFFSET_RECORD_COUNT + LENGTH_RECORD_COUNT; // 51
321324
}
322325

323326
public void write(final RandomAccessFile raf) throws IOException {
324327
raf.seek(0);
325-
write(this.buf);
326-
raf.write(this.buf);
328+
write(this.headerBuf);
329+
raf.write(this.headerBuf);
327330
this.dirty = false;
328331
}
329332

@@ -351,4 +354,27 @@ public ReentrantReadWriteLock.WriteLock writeLock() {
351354
writeLock.lock();
352355
return writeLock;
353356
}
357+
358+
359+
protected static class AbstractPagedFileHeaderData {
360+
final short version;
361+
final short headerSize;
362+
final int pageSize;
363+
final long totalCount;
364+
final long firstFreePage;
365+
final long lastFreePage;
366+
final byte pageHeaderSize;
367+
final short maxKeySize;
368+
369+
private AbstractPagedFileHeaderData(final short version, final short headerSize, final int pageSize, final long totalCount, final long firstFreePage, final long lastFreePage, final byte pageHeaderSize, final short maxKeySize) {
370+
this.version = version;
371+
this.headerSize = headerSize;
372+
this.pageSize = pageSize;
373+
this.totalCount = totalCount;
374+
this.firstFreePage = firstFreePage;
375+
this.lastFreePage = lastFreePage;
376+
this.pageHeaderSize = pageHeaderSize;
377+
this.maxKeySize = maxKeySize;
378+
}
379+
}
354380
}

exist-core/src/main/java/org/exist/storage/btree/BTreeFileHeader.java

Lines changed: 69 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
import org.exist.util.ByteConversion;
8585

8686
import java.io.IOException;
87+
import java.io.RandomAccessFile;
8788

8889
/**
8990
* BTree File Header.
@@ -93,37 +94,73 @@
9394
*/
9495
public class BTreeFileHeader extends AbstractPagedFileHeader implements PagedFileHeader {
9596

96-
private final static int MIN_SPACE_PER_KEY = 32;
97+
private static final int MIN_SPACE_PER_KEY = 32;
9798

99+
private static final int LENGTH_ROOT_PAGE = 8; // sizeof(long)
100+
protected static final int LENGTH_FIXED_LEN = 2; // sizeof(short)
101+
102+
private static final int OFFSET_ROOT_PAGE = OFFSET_RECORD_COUNT + LENGTH_RECORD_COUNT; // 51
103+
protected static final int OFFSET_FIXED_LEN = OFFSET_ROOT_PAGE + LENGTH_ROOT_PAGE; // 59
104+
105+
//<editor-fold desc="Mutable state">
98106
private long rootPage = 0;
99107
private short fixedLen = -1;
108+
//</editor-fold>
100109

101-
public BTreeFileHeader(final short fileVersion, final long pageCount, final int pageSize) {
102-
super(fileVersion, pageCount, pageSize);
110+
protected BTreeFileHeader(final short version, final short headerSize, final int pageSize, final byte pageHeaderSize, final short maxKeySize, final long firstFreePage, final long lastFreePage, final long totalCount, final long rootPage, final short fixedLen) {
111+
super(version, headerSize, pageSize, pageHeaderSize, maxKeySize, firstFreePage, lastFreePage, totalCount);
112+
this.rootPage = rootPage;
113+
this.fixedLen = fixedLen;
103114
}
104115

105-
public BTreeFileHeader(final short fileVersion, final int pageSize) {
106-
super(fileVersion, 1024, pageSize);
116+
protected BTreeFileHeader(final short version, final long pageCount, final int pageSize) {
117+
super(version, pageCount, pageSize);
118+
this.rootPage = 0;
119+
this.fixedLen = -1;
107120
}
108121

109-
@Override
110-
protected int read(final byte[] buf) throws IOException {
111-
int offset = super.read(buf);
112-
rootPage = ByteConversion.byteToLong(buf, offset);
113-
offset += 8;
114-
fixedLen = ByteConversion.byteToShort(buf, offset);
115-
offset += 2;
116-
return offset;
122+
public static BTreeFileHeader createNew(final short version, final long pageCount, final int pageSize) {
123+
return new BTreeFileHeader(version, pageCount, pageSize);
124+
}
125+
126+
public static BTreeFileHeader load(final RandomAccessFile raf) throws IOException {
127+
// file header is at the start of the file, so always reposition to the start of the file
128+
raf.seek(0);
129+
130+
// read the entire BTreeFileHeader from the file
131+
final int headerBufSize = OFFSET_FIXED_LEN + LENGTH_FIXED_LEN; // 61
132+
final byte[] headerBuf = new byte[headerBufSize];
133+
raf.read(headerBuf);
134+
135+
final BTreeFileHeaderData bTreeFileHeaderData = readBTreeFileHeaderData(headerBuf);
136+
return new BTreeFileHeader(
137+
bTreeFileHeaderData.abstractPagedFileHeaderData.version,
138+
bTreeFileHeaderData.abstractPagedFileHeaderData.headerSize,
139+
bTreeFileHeaderData.abstractPagedFileHeaderData.pageSize,
140+
bTreeFileHeaderData.abstractPagedFileHeaderData.pageHeaderSize,
141+
bTreeFileHeaderData.abstractPagedFileHeaderData.maxKeySize,
142+
bTreeFileHeaderData.abstractPagedFileHeaderData.firstFreePage,
143+
bTreeFileHeaderData.abstractPagedFileHeaderData.lastFreePage,
144+
bTreeFileHeaderData.abstractPagedFileHeaderData.totalCount,
145+
bTreeFileHeaderData.rootPage,
146+
bTreeFileHeaderData.fixedLen
147+
);
148+
}
149+
150+
protected static BTreeFileHeaderData readBTreeFileHeaderData(final byte[] headerBuf) {
151+
final AbstractPagedFileHeaderData abstractPagedFileHeaderData = readAbstractPagedFileHeaderData(headerBuf);
152+
final long rootPage = ByteConversion.byteToLong(headerBuf, OFFSET_ROOT_PAGE);
153+
final short fixedLen = ByteConversion.byteToShort(headerBuf, OFFSET_FIXED_LEN);
154+
155+
return new BTreeFileHeaderData(abstractPagedFileHeaderData, rootPage, fixedLen);
117156
}
118157

119158
@Override
120159
protected int write(final byte[] buf) throws IOException {
121-
int offset = super.write(buf);
122-
ByteConversion.longToByte(rootPage, buf, offset);
123-
offset += 8;
124-
ByteConversion.shortToByte(fixedLen, buf, offset);
125-
offset += 2;
126-
return offset;
160+
super.write(buf);
161+
ByteConversion.longToByte(rootPage, buf, OFFSET_ROOT_PAGE);
162+
ByteConversion.shortToByte(fixedLen, buf, OFFSET_FIXED_LEN);
163+
return OFFSET_FIXED_LEN + LENGTH_FIXED_LEN; // 61;
127164
}
128165

129166
/**
@@ -157,4 +194,17 @@ public void setFixedKeyLen(short keyLen) {
157194
public int getMaxKeySize() {
158195
return (getWorkSize() / 2) - MIN_SPACE_PER_KEY;
159196
}
197+
198+
199+
protected static class BTreeFileHeaderData {
200+
final AbstractPagedFileHeaderData abstractPagedFileHeaderData;
201+
final long rootPage;
202+
final short fixedLen;
203+
204+
private BTreeFileHeaderData(final AbstractPagedFileHeaderData abstractPagedFileHeaderData, final long rootPage, final short fixedLen) {
205+
this.abstractPagedFileHeaderData = abstractPagedFileHeaderData;
206+
this.rootPage = rootPage;
207+
this.fixedLen = fixedLen;
208+
}
209+
}
160210
}

0 commit comments

Comments
 (0)