mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GT-3294 Added support for DB FixedField with improved indexing.
This commit is contained in:
parent
14d4c87ef4
commit
fcb3151f94
224 changed files with 9574 additions and 7913 deletions
|
@ -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 ( < 0: no leaf)
|
||||
* @param nextLeafId node buffer id for next leaf ( < 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 <= 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;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue