GT-3294 Added support for DB FixedField with improved indexing.

This commit is contained in:
ghidra1 2020-02-24 18:02:01 -05:00
parent 14d4c87ef4
commit fcb3151f94
224 changed files with 9574 additions and 7913 deletions

View file

@ -1,6 +1,5 @@
/* ###
* IP: GHIDRA
* REVIEWED: YES
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,11 +15,10 @@
*/
package db;
import ghidra.util.exception.AssertException;
import java.io.IOException;
import db.buffers.DataBuffer;
import ghidra.util.exception.AssertException;
/**
* <code>FixedRecNode</code> is an implementation of a BTree leaf node
@ -37,75 +35,68 @@ import db.buffers.DataBuffer;
class FixedRecNode extends LongKeyRecordNode {
private static final int HEADER_SIZE = RECORD_LEAF_HEADER_SIZE;
private static final int ENTRY_BASE_OFFSET = HEADER_SIZE;
private static final int KEY_SIZE = 8;
private static final int[] EMPTY_ID_LIST = new int[0];
private int entrySize;
private int recordLength;
/**
* Construct an existing long-key fixed-length record leaf node.
* @param nodeMgr table node manager instance
* @param buf node buffer
* @param recordLength fixed record length
*/
FixedRecNode(NodeMgr nodeMgr, DataBuffer buf, int recordLength) {
super(nodeMgr, buf);
this.recordLength = recordLength;
entrySize = KEY_SIZE + recordLength;
}
/**
* Construct a new long-key fixed-length record leaf node.
* @param nodeMgr table node manager instance
* @param recordLength fixed record length
* @param prevLeafId node buffer id for previous leaf ( &lt; 0: no leaf)
* @param nextLeafId node buffer id for next leaf ( &lt; 0 : no leaf)
* @throws IOException
* @throws IOException thrown if IO error occurs
*/
FixedRecNode(NodeMgr nodeMgr, int recordLength, int prevLeafId, int nextLeafId) throws IOException {
FixedRecNode(NodeMgr nodeMgr, int recordLength, int prevLeafId, int nextLeafId)
throws IOException {
super(nodeMgr, NodeMgr.LONGKEY_FIXED_REC_NODE, prevLeafId, nextLeafId);
this.recordLength = recordLength;
entrySize = KEY_SIZE + recordLength;
}
/*
* @see ghidra.framework.store.db.LongKeyRecordNode#createNewLeaf(int, int)
*/
@Override
LongKeyRecordNode createNewLeaf(int prevLeafId, int nextLeafId) throws IOException {
LongKeyRecordNode createNewLeaf(int prevLeafId, int nextLeafId) throws IOException {
return new FixedRecNode(nodeMgr, recordLength, prevLeafId, nextLeafId);
}
/*
* @see ghidra.framework.store.db.LongKeyNode#getKey(int)
*/
@Override
long getKey(int index) {
return buffer.getLong(ENTRY_BASE_OFFSET + (index * entrySize));
long getKey(int index) {
return buffer.getLong(getKeyOffset(index));
}
// /**
// * Store a key at the specified index
// * @param index key index
// * @param key key value
// */
// private void putKey(int index, long key) {
// buffer.putLong(ENTRY_BASE_OFFSET + (index * entrySize), key);
// }
@Override
public int getKeyOffset(int index) {
return ENTRY_BASE_OFFSET + (index * entrySize);
}
/**
* Get the record offset within the buffer
* @param index key index
* @return record offset
*/
private int getRecordOffset(int index) {
@Override
public int getRecordOffset(int index) {
return ENTRY_BASE_OFFSET + (index * entrySize);
}
/**
* Shift all records by one starting with index to the end.
* @param index the smaller key index (0 &lt;= index1)
@ -113,49 +104,41 @@ class FixedRecNode extends LongKeyRecordNode {
* one record.
*/
private void shiftRecords(int index, boolean rightShift) {
// No movement needed for appended record
if (index == keyCount)
return;
// Determine block to be moved
int start = getRecordOffset(index);
int end = getRecordOffset(keyCount);
int len = end - start;
// Move record data
int offset = start + (rightShift ? entrySize : -entrySize);
buffer.move(start, offset, len);
}
/*
* @see ghidra.framework.store.db.LongKeyRecordNode#remove(int)
*/
@Override
void remove(int index) {
if (index < 0 || index >= keyCount)
throw new AssertException();
@Override
public void remove(int index) {
if (index < 0 || index >= keyCount)
throw new AssertException();
shiftRecords(index + 1, false);
setKeyCount(keyCount - 1);
setKeyCount(keyCount - 1);
}
/*
* @see ghidra.framework.store.db.LongKeyRecordNode#insertRecord(int, ghidra.framework.store.db.Record)
*/
@Override
boolean insertRecord(int index, Record record) throws IOException {
// Check for use of indirect chained record node(s)
// int len = record.length();
boolean insertRecord(int index, Record record) throws IOException {
if (keyCount == ((buffer.length() - HEADER_SIZE) / entrySize))
if (keyCount == ((buffer.length() - HEADER_SIZE) / entrySize)) {
return false; // insufficient space for record storage
}
// Make room for new record
shiftRecords(index, true);
// Store new record
int offset = getRecordOffset(index);
buffer.putLong(offset, record.getKey());
@ -165,21 +148,15 @@ throw new AssertException();
return true;
}
/*
* @see ghidra.framework.store.db.LongKeyRecordNode#updateRecord(int, ghidra.framework.store.db.Record)
*/
@Override
LongKeyNode updateRecord(int index, Record record) throws IOException {
LongKeyNode updateRecord(int index, Record record) throws IOException {
int offset = getRecordOffset(index) + KEY_SIZE;
record.write(buffer, offset);
return getRoot();
}
/*
* @see ghidra.framework.store.db.LongKeyRecordNode#getRecord(long, ghidra.framework.store.db.Schema)
*/
@Override
Record getRecord(long key, Schema schema) throws IOException {
Record getRecord(long key, Schema schema) throws IOException {
int index = getKeyIndex(key);
if (index < 0)
return null;
@ -188,50 +165,39 @@ throw new AssertException();
return record;
}
/*
* @see ghidra.framework.store.db.LongKeyRecordNode#getRecord(ghidra.framework.store.db.Schema, int)
*/
@Override
Record getRecord(Schema schema, int index) throws IOException {
public Record getRecord(Schema schema, int index) throws IOException {
long key = getKey(index);
Record record = schema.createRecord(key);
record.read(buffer, getRecordOffset(index) + KEY_SIZE);
return record;
return record;
}
/*
* @see ghidra.framework.store.db.LongKeyRecordNode#splitData(ghidra.framework.store.db.LongKeyRecordNode)
*/
@Override
void splitData(LongKeyRecordNode newRightLeaf) {
void splitData(LongKeyRecordNode newRightLeaf) {
FixedRecNode rightNode = (FixedRecNode) newRightLeaf;
int splitIndex = keyCount / 2;
int count = keyCount - splitIndex;
int start = getRecordOffset(splitIndex); // start of block to be moved
int end = getRecordOffset(keyCount); // end of block to be moved
int splitLen = end - start; // length of block to be moved
// Copy data to new leaf node
rightNode.buffer.copy(ENTRY_BASE_OFFSET, buffer, start, splitLen);
rightNode.buffer.copy(ENTRY_BASE_OFFSET, buffer, start, splitLen);
// Adjust key counts
setKeyCount(keyCount - count);
rightNode.setKeyCount(count);
}
/*
* @see ghidra.framework.store.db.LongKeyNode#delete()
*/
@Override
public void delete() throws IOException {
public void delete() throws IOException {
nodeMgr.deleteNode(this);
}
/*
* @see ghidra.framework.store.db.BTreeNode#getBufferReferences()
*/
@Override
public int[] getBufferReferences() {
return EMPTY_ID_LIST;
}