Example #1
0
 /**
  * Fill the current buffer with bytes from the specified array from the specified offset.
  *
  * @param s source array
  * @param o offset from the beginning of the array
  * @return number of written bytes
  */
 private int write(final byte[] s, final int o) {
   final Buffer bf = bm.current();
   final int len = Math.min(IO.BLOCKSIZE, s.length - o);
   System.arraycopy(s, o, bf.data, 0, len);
   bf.dirty = true;
   return len;
 }
Example #2
0
 @Override
 public void write1(final int pre, final int off, final int v) {
   final int o = off + cursor(pre);
   final Buffer bf = bm.current();
   final byte[] b = bf.data;
   b[o] = (byte) v;
   bf.dirty = true;
 }
Example #3
0
  /**
   * Reads a block from disk.
   *
   * @param b block to fetch
   */
  private void readBlock(final int b) {
    if (!bm.cursor(b)) return;

    final Buffer bf = bm.current();
    try {
      if (bf.dirty) writeBlock(bf);
      bf.pos = b;
      if (b >= blocks) {
        blocks = b + 1;
      } else {
        file.seek(bf.pos * IO.BLOCKSIZE);
        file.readFully(bf.data);
      }
    } catch (final IOException ex) {
      Util.stack(ex);
    }
  }
Example #4
0
 @Override
 protected void copy(final byte[] entries, final int pre, final int last) {
   for (int o = 0, i = pre; i < last; ++i, o += IO.NODESIZE) {
     final int off = cursor(i);
     final Buffer bf = bm.current();
     System.arraycopy(entries, o, bf.data, off, IO.NODESIZE);
     bf.dirty = true;
   }
 }
Example #5
0
 @Override
 public synchronized int read4(final int pre, final int off) {
   final int o = off + cursor(pre);
   final byte[] b = bm.current().data;
   return ((b[o] & 0xFF) << 24)
       + ((b[o + 1] & 0xFF) << 16)
       + ((b[o + 2] & 0xFF) << 8)
       + (b[o + 3] & 0xFF);
 }
Example #6
0
 @Override
 public void write4(final int pre, final int off, final int v) {
   final int o = off + cursor(pre);
   final Buffer bf = bm.current();
   final byte[] b = bf.data;
   b[o] = (byte) (v >>> 24);
   b[o + 1] = (byte) (v >>> 16);
   b[o + 2] = (byte) (v >>> 8);
   b[o + 3] = (byte) v;
   bf.dirty = true;
 }
Example #7
0
  @Override
  public synchronized void flush() throws IOException {
    for (final Buffer b : bm.all()) if (b.dirty) writeBlock(b);
    if (!dirty) return;

    try (final DataOutput out = new DataOutput(meta.dbfile(DATATBL + 'i'))) {
      out.writeNum(blocks);
      out.writeNum(used);

      // due to legacy issues, number of blocks is written several times
      out.writeNum(blocks);
      for (int a = 0; a < blocks; a++) out.writeNum(fpres[a]);
      out.writeNum(blocks);
      for (int a = 0; a < blocks; a++) out.writeNum(pages[a]);

      out.writeLongs(usedPages.toArray());
    }
    dirty = false;
  }
Example #8
0
 /**
  * Convenience method for copying blocks.
  *
  * @param s source array
  * @param sp source position
  * @param d destination array
  * @param dp destination position
  * @param l source length
  */
 private void copy(final byte[] s, final int sp, final byte[] d, final int dp, final int l) {
   System.arraycopy(s, sp << IO.NODEPOWER, d, dp << IO.NODEPOWER, l << IO.NODEPOWER);
   bm.current().dirty = true;
 }
Example #9
0
  @Override
  public void insert(final int pre, final byte[] entries) {
    final int nnew = entries.length;
    if (nnew == 0) return;
    dirty();

    // number of records to be inserted
    final int nr = nnew >>> IO.NODEPOWER;

    int split = 0;
    if (used == 0) {
      // special case: insert new data into first block if database is empty
      readPage(0);
      usedPages.set(0);
      ++used;
    } else if (pre > 0) {
      // find the offset within the block where the new records will be inserted
      split = cursor(pre - 1) + IO.NODESIZE;
    } else {
      // all insert operations will add data after first node.
      // i.e., there is no "insert before first document" statement
      throw Util.notExpected("Insertion at beginning of populated table.");
    }

    // number of bytes occupied by old records in the current block
    final int nold = npre - fpre << IO.NODEPOWER;
    // number of bytes occupied by old records which will be moved at the end
    final int moved = nold - split;

    // special case: all entries fit in the current block
    Buffer bf = bm.current();
    if (nold + nnew <= IO.BLOCKSIZE) {
      Array.move(bf.data, split, nnew, moved);
      System.arraycopy(entries, 0, bf.data, split, nnew);
      bf.dirty = true;

      // increment first pre-values of blocks after the last modified block
      for (int i = page + 1; i < used; ++i) fpres[i] += nr;
      // update cached variables (fpre is not changed)
      npre += nr;
      meta.size += nr;
      return;
    }

    // append old entries at the end of the new entries
    final byte[] all = new byte[nnew + moved];
    System.arraycopy(entries, 0, all, 0, nnew);
    System.arraycopy(bf.data, split, all, nnew, moved);

    // fill in the current block with new entries
    // number of bytes which fit in the first block
    int nrem = IO.BLOCKSIZE - split;
    if (nrem > 0) {
      System.arraycopy(all, 0, bf.data, split, nrem);
      bf.dirty = true;
    }

    // number of new required blocks and remaining bytes
    final int req = all.length - nrem;
    int needed = req / IO.BLOCKSIZE;
    final int remain = req % IO.BLOCKSIZE;

    if (remain > 0) {
      // check if the last entries can fit in the block after the current one
      if (page + 1 < used) {
        final int o = occSpace(page + 1) << IO.NODEPOWER;
        if (remain <= IO.BLOCKSIZE - o) {
          // copy the last records
          readPage(page + 1);
          bf = bm.current();
          System.arraycopy(bf.data, 0, bf.data, remain, o);
          System.arraycopy(all, all.length - remain, bf.data, 0, remain);
          bf.dirty = true;
          // reduce the pre value, since it will be later incremented with nr
          fpres[page] -= remain >>> IO.NODEPOWER;
          // go back to the previous block
          readPage(page - 1);
        } else {
          // there is not enough space in the block - allocate a new one
          ++needed;
        }
      } else {
        // this is the last block - allocate a new one
        ++needed;
      }
    }

    // number of expected blocks: existing blocks + needed block - empty blocks
    final int exp = blocks + needed - (blocks - used);
    if (exp > fpres.length) {
      // resize directory arrays if existing ones are too small
      final int ns = Math.max(fpres.length << 1, exp);
      fpres = Arrays.copyOf(fpres, ns);
      pages = Arrays.copyOf(pages, ns);
    }

    // make place for the blocks where the new entries will be written
    Array.move(fpres, page + 1, needed, used - page - 1);
    Array.move(pages, page + 1, needed, used - page - 1);

    // write the all remaining entries
    while (needed-- > 0) {
      freeBlock();
      nrem += write(all, nrem);
      fpres[page] = fpres[page - 1] + IO.ENTRIES;
      pages[page] = (int) bm.current().pos;
    }

    // increment all fpre values after the last modified block
    for (int i = page + 1; i < used; ++i) fpres[i] += nr;

    meta.size += nr;

    // update cached variables
    fpre = fpres[page];
    npre = page + 1 < used && fpres[page + 1] < meta.size ? fpres[page + 1] : meta.size;
  }
Example #10
0
  @Override
  public void delete(final int pre, final int nr) {
    if (nr == 0) return;
    dirty();

    // get first block
    cursor(pre);

    // some useful variables to make code more readable
    int from = pre - fpre;
    final int last = pre + nr;

    // check if all entries are in current block: handle and return
    if (last - 1 < npre) {
      final Buffer bf = bm.current();
      copy(bf.data, from + nr, bf.data, from, npre - last);
      updatePre(nr);

      // if whole block was deleted, remove it from the index
      if (npre == fpre) {
        // mark the block as empty
        usedPages.clear(pages[page]);

        Array.move(fpres, page + 1, -1, used - page - 1);
        Array.move(pages, page + 1, -1, used - page - 1);

        --used;
        readPage(page);
      }
      return;
    }

    // handle blocks whose entries are to be deleted entirely

    // first count them
    int unused = 0;
    while (npre < last) {
      if (from == 0) {
        ++unused;
        // mark the blocks as empty; range clear cannot be used because the
        // blocks may not be consecutive
        usedPages.clear(pages[page]);
      }
      setPage(page + 1);
      from = 0;
    }

    // if the last block is empty, clear the corresponding bit
    readBlock(pages[page]);
    final Buffer bf = bm.current();
    if (npre == last) {
      usedPages.clear((int) bf.pos);
      ++unused;
      if (page < used - 1) readPage(page + 1);
      else ++page;
    } else {
      // delete entries at beginning of current (last) block
      copy(bf.data, last - fpre, bf.data, 0, npre - last);
    }

    // now remove them from the index
    if (unused > 0) {
      Array.move(fpres, page, -unused, used - page);
      Array.move(pages, page, -unused, used - page);
      used -= unused;
      page -= unused;
    }

    // update index entry for this block
    fpres[page] = pre;
    fpre = pre;
    updatePre(nr);
  }
Example #11
0
 @Override
 public synchronized int read1(final int pre, final int off) {
   final int o = off + cursor(pre);
   final byte[] b = bm.current().data;
   return b[o] & 0xFF;
 }