/** * Remove an entry with the given key from the BTree. * * @param key Removal key * @return Value associated with the key, or null if no entry with given key existed in the BTree. */ public synchronized Object remove(Object key) throws IOException { if (key == null) { throw new IllegalArgumentException("Argument 'key' is null"); } BPage rootPage = getRoot(); if (rootPage == null) { return null; } boolean dirty = false; BPage.RemoveResult remove = rootPage.remove(_height, key); if (remove._underflow && rootPage.isEmpty()) { _height -= 1; dirty = true; // TODO: check contract for BPages to be removed from recman. if (_height == 0) { _root = 0; } else { _root = rootPage.childBPage(_pageSize - 1)._recid; } } if (remove._value != null) { _entries--; dirty = true; } if (dirty) { _recman.update(_recid, this); } return remove._value; }
/** * Load a persistent BTree. * * @param recman RecordManager used to store the persistent btree * @param recid Record id of the BTree */ public static BTree load(RecordManager recman, long recid) throws IOException { BTree btree = (BTree) recman.fetch(recid); btree._recid = recid; btree._recman = recman; btree._bpageSerializer = new BPage(); btree._bpageSerializer._btree = btree; return btree; }
/** * Insert an entry in the BTree. * * <p>The BTree cannot store duplicate entries. An existing entry can be replaced using the <code> * replace</code> flag. If an entry with the same key already exists in the BTree, its value is * returned. * * @param key Insert key * @param value Insert value * @param replace Set to true to replace an existing key-value pair. * @return Existing value, if any. */ public synchronized Object insert(Object key, Object value, boolean replace) throws IOException { if (key == null) { throw new IllegalArgumentException("Argument 'key' is null"); } if (value == null) { throw new IllegalArgumentException("Argument 'value' is null"); } BPage rootPage = getRoot(); if (rootPage == null) { // BTree is currently empty, create a new root BPage if (DEBUG) { System.out.println("BTree.insert() new root BPage"); } rootPage = new BPage(this, key, value); _root = rootPage._recid; _height = 1; _entries = 1; _recman.update(_recid, this); return null; } else { BPage.InsertResult insert = rootPage.insert(_height, key, value, replace); boolean dirty = false; if (insert._overflow != null) { // current root page overflowed, we replace with a new root page if (DEBUG) { System.out.println("BTree.insert() replace root BPage due to overflow"); } rootPage = new BPage(this, rootPage, insert._overflow); _root = rootPage._recid; _height += 1; dirty = true; } if (insert._existing == null) { _entries++; dirty = true; } if (dirty) { _recman.update(_recid, this); } // insert might have returned an existing value return insert._existing; } }
/** Return the root BPage, or null if it doesn't exist. */ private BPage getRoot() throws IOException { if (_root == 0) { return null; } BPage root = (BPage) _recman.fetch(_root, _bpageSerializer); root._recid = _root; root._btree = this; return root; }
/** * Create a new persistent BTree with the given number of entries per node. * * @param recman Record manager used for persistence. * @param comparator Comparator used to order index entries * @param keySerializer Serializer used to serialize index keys (optional) * @param valueSerializer Serializer used to serialize index values (optional) * @param pageSize Number of entries per page (must be even). */ public static BTree createInstance( RecordManager recman, Comparator comparator, Serializer keySerializer, Serializer valueSerializer, int pageSize) throws IOException { BTree btree; if (recman == null) { throw new IllegalArgumentException("Argument 'recman' is null"); } if (comparator == null) { throw new IllegalArgumentException("Argument 'comparator' is null"); } if (!(comparator instanceof Serializable)) { throw new IllegalArgumentException("Argument 'comparator' must be serializable"); } if (keySerializer != null && !(keySerializer instanceof Serializable)) { throw new IllegalArgumentException("Argument 'keySerializer' must be serializable"); } if (valueSerializer != null && !(valueSerializer instanceof Serializable)) { throw new IllegalArgumentException("Argument 'valueSerializer' must be serializable"); } // make sure there's an even number of entries per BPage if ((pageSize & 1) != 0) { throw new IllegalArgumentException("Argument 'pageSize' must be even"); } btree = new BTree(); btree._recman = recman; btree._comparator = comparator; btree._keySerializer = keySerializer; btree._valueSerializer = valueSerializer; btree._pageSize = pageSize; btree._bpageSerializer = new BPage(); btree._bpageSerializer._btree = btree; btree._recid = recman.insert(btree); return btree; }