Esempio n. 1
0
 /**
  * Creates a new root block for the B-tree. The new root will have two children: the old root, and
  * the specified block. Since the root must always be in block 0 of the file, the contents of the
  * old root will get transferred to a new block.
  *
  * @param e the directory entry to be added as a child of the new root
  */
 public void makeNewRoot(DirEntry e) {
   Constant firstval = contents.getDataVal(0);
   int level = contents.getFlag();
   Block newblk = contents.split(0, level); // ie, transfer all the records
   DirEntry oldroot = new DirEntry(firstval, newblk.number());
   insertEntry(oldroot);
   insertEntry(e);
   contents.setFlag(level + 1);
 }
Esempio n. 2
0
 /**
  * Returns the block number of the B-tree leaf block that contains the specified search key.
  *
  * @param searchkey the search key value
  * @return the block number of the leaf block containing that search key
  */
 public int search(Constant searchkey) {
   Block childblk = findChildBlock(searchkey);
   while (contents.getFlag() > 0) {
     contents.close();
     contents = new BTreePage(childblk, ti, tx);
     childblk = findChildBlock(searchkey);
   }
   return childblk.number();
 }
Esempio n. 3
0
  private long save() {
    int currentUnsavedMemory = unsavedMemory;
    long version = ++currentVersion;
    long time = getTimeSinceCreation();
    lastCommitTime = time;

    WriteBuffer buff = getWriteBuffer();
    BTreeChunk c = new BTreeChunk(++lastChunkId);
    chunks.put(c.id, c);
    c.time = time;
    c.version = version;
    c.pagePositions = new ArrayList<Long>();

    BTreePage p = map.root;
    if (p.getTotalCount() > 0) {
      p.writeUnsavedRecursive(c, buff);
      c.rootPagePos = p.getPos();
      p.writeEnd();
    }

    c.pagePositionsOffset = buff.position();
    for (long pos : c.pagePositions) buff.putLong(pos);

    int chunkBodyLength = buff.position();
    chunkBodyLength = MathUtils.roundUpInt(chunkBodyLength, BLOCK_SIZE);
    buff.limit(chunkBodyLength);
    buff.position(0);

    c.blockCount =
        chunkBodyLength / BLOCK_SIZE + CHUNK_HEADER_BLOCKS; // include chunk header(2 blocks).
    c.fileStorage = getFileStorage(c.id);

    // chunk header
    writeChunkHeader(c);
    // chunk body
    write(c.fileStorage, CHUNK_HEADER_SIZE, buff.getBuffer());
    c.fileStorage.sync();

    for (BTreeChunk chunk : chunks.values()) {
      if (chunk.changed) {
        writeChunkHeader(chunk);
        chunk.fileStorage.sync();
        chunk.changed = false;
      }
    }

    releaseWriteBuffer(buff);

    // some pages might have been changed in the meantime (in the newest version)
    unsavedMemory = Math.max(0, unsavedMemory - currentUnsavedMemory);
    lastStoredVersion = version - 1;

    return version;
  }
Esempio n. 4
0
 /**
  * Inserts a new directory entry into the B-tree block. If the block is at level 0, then the entry
  * is inserted there. Otherwise, the entry is inserted into the appropriate child node, and the
  * return value is examined. A non-null return value indicates that the child node split, and so
  * the returned entry is inserted into this block. If this block splits, then the method similarly
  * returns the entry information of the new block to its caller; otherwise, the method returns
  * null.
  *
  * @param e the directory entry to be inserted
  * @return the directory entry of the newly-split block, if one exists; otherwise, null
  */
 public DirEntry insert(DirEntry e) {
   if (contents.getFlag() == 0) return insertEntry(e);
   Block childblk = findChildBlock(e.dataVal());
   BTreeDir child = new BTreeDir(childblk, ti, tx);
   DirEntry myentry = child.insert(e);
   child.close();
   return (myentry != null) ? insertEntry(myentry) : null;
 }
Esempio n. 5
0
 /**
  * Read a page.
  *
  * @param pos the page position
  * @return the page
  */
 BTreePage readPage(long pos) {
   if (pos == 0) {
     throw DataUtils.newIllegalStateException(DataUtils.ERROR_FILE_CORRUPT, "Position 0");
   }
   BTreePage p = cache == null ? null : cache.get(pos);
   if (p == null) {
     BTreeChunk c = getChunk(pos);
     long filePos = CHUNK_HEADER_SIZE + DataUtils.getPageOffset(pos);
     if (filePos < 0) {
       throw DataUtils.newIllegalStateException(
           DataUtils.ERROR_FILE_CORRUPT, "Negative position {0}", filePos);
     }
     long maxPos = c.blockCount * BLOCK_SIZE;
     p = BTreePage.read(c.fileStorage, pos, map, filePos, maxPos);
     cachePage(pos, p, p.getMemory());
   }
   return p;
 }
Esempio n. 6
0
 private DirEntry insertEntry(DirEntry e) {
   int newslot = 1 + contents.findSlotBefore(e.dataVal());
   contents.insertDir(newslot, e.dataVal(), e.blockNumber());
   if (!contents.isFull()) return null;
   // else page is full, so split it
   int level = contents.getFlag();
   int splitpos = contents.getNumRecs() / 2;
   Constant splitval = contents.getDataVal(splitpos);
   Block newblk = contents.split(splitpos, level);
   return new DirEntry(splitval, newblk.number());
 }
Esempio n. 7
0
 /**
  * Compact the storage by moving all live pages to new chunks.
  *
  * @return if anything was written
  */
 public synchronized boolean compactRewriteFully() {
   checkOpen();
   if (lastChunk == null) {
     // nothing to do
     return false;
   }
   BTreeCursor<?, ?> cursor = (BTreeCursor<?, ?>) map.cursor(null);
   BTreePage lastPage = null;
   while (cursor.hasNext()) {
     cursor.next();
     BTreePage p = cursor.getPage();
     if (p == lastPage) {
       continue;
     }
     Object k = p.getKey(0);
     Object v = p.getValue(0);
     map.put(k, v);
     lastPage = p;
   }
   commitAndSave();
   // TODO 删除之前的所有chunk
   return true;
 }
Esempio n. 8
0
 /** Closes the directory page. */
 public void close() {
   contents.close();
 }
Esempio n. 9
0
 private Block findChildBlock(Constant searchkey) {
   int slot = contents.findSlotBefore(searchkey);
   if (contents.getDataVal(slot + 1).equals(searchkey)) slot++;
   int blknum = contents.getChildNum(slot);
   return new Block(filename, blknum);
 }