예제 #1
0
  public void writeBytes(int record, ByteSequence bytes, boolean fixedSize) throws IOException {
    synchronized (myLock) {
      final int requiredLength = bytes.getLength();
      final int currentCapacity = myRecordsTable.getCapacity(record);

      final int currentSize = myRecordsTable.getSize(record);
      assert currentSize >= 0;

      if (requiredLength == 0 && currentSize == 0) return;

      final long address;
      if (currentCapacity >= requiredLength) {
        address = myRecordsTable.getAddress(record);
      } else {
        myDataTable.reclaimSpace(currentCapacity);

        int newCapacity =
            fixedSize
                ? requiredLength
                : myCapacityAllocationPolicy.calculateCapacity(requiredLength);
        if (newCapacity < requiredLength) newCapacity = requiredLength;
        address = myDataTable.allocateSpace(newCapacity);
        myRecordsTable.setAddress(record, address);
        myRecordsTable.setCapacity(record, newCapacity);
      }

      myDataTable.writeBytes(address, bytes.getBytes(), bytes.getOffset(), bytes.getLength());
      myRecordsTable.setSize(record, requiredLength);
    }
  }
예제 #2
0
  public boolean flushSome() {
    synchronized (myLock) {
      boolean okRecords = myRecordsTable.flushSome(MAX_PAGES_TO_FLUSH_AT_A_TIME);
      boolean okData = myDataTable.flushSome(MAX_PAGES_TO_FLUSH_AT_A_TIME);

      return okRecords && okData;
    }
  }
예제 #3
0
 public void checkSanity(final int record) {
   synchronized (myLock) {
     final int size = myRecordsTable.getSize(record);
     assert size >= 0;
     final long address = myRecordsTable.getAddress(record);
     assert address >= 0;
     assert address + size < myDataTable.getFileSize();
   }
 }
예제 #4
0
  protected byte[] readBytes(int record) throws IOException {
    synchronized (myLock) {
      final int length = myRecordsTable.getSize(record);
      if (length == 0) return ArrayUtil.EMPTY_BYTE_ARRAY;
      assert length > 0;

      final long address = myRecordsTable.getAddress(record);
      byte[] result = new byte[length];
      myDataTable.readBytes(address, result);

      return result;
    }
  }
예제 #5
0
  private void compact(final String path) {
    synchronized (myLock) {
      LOG.info(
          "Space waste in " + path + " is " + myDataTable.getWaste() + " bytes. Compacting now.");
      long start = System.currentTimeMillis();

      try {
        File newDataFile = new File(path + ".storageData.backup");
        FileUtil.delete(newDataFile);
        FileUtil.createIfDoesntExist(newDataFile);

        File oldDataFile = new File(path + DATA_EXTENSION);
        DataTable newDataTable = new DataTable(newDataFile, myPool);

        final int count = myRecordsTable.getRecordsCount();
        for (int i = 1; i <= count; i++) {
          final long addr = myRecordsTable.getAddress(i);
          final int size = myRecordsTable.getSize(i);

          if (size > 0) {
            assert addr > 0;

            final int capacity = myCapacityAllocationPolicy.calculateCapacity(size);
            final long newaddr = newDataTable.allocateSpace(capacity);
            final byte[] bytes = new byte[size];
            myDataTable.readBytes(addr, bytes);
            newDataTable.writeBytes(newaddr, bytes);
            myRecordsTable.setAddress(i, newaddr);
            myRecordsTable.setCapacity(i, capacity);
          }
        }

        myDataTable.dispose();
        newDataTable.dispose();

        if (!FileUtil.delete(oldDataFile)) {
          throw new IOException("Can't delete file: " + oldDataFile);
        }

        newDataFile.renameTo(oldDataFile);
        myDataTable = new DataTable(oldDataFile, myPool);
      } catch (IOException e) {
        LOG.info("Compact failed: " + e.getMessage());
      }

      long timedelta = System.currentTimeMillis() - start;
      LOG.info("Done compacting in " + timedelta + "msec.");
    }
  }
예제 #6
0
  private void tryInit(String storageFilePath, PagePool pool, int retryCount) throws IOException {
    convertFromOldExtensions(storageFilePath);

    final File recordsFile = new File(storageFilePath + INDEX_EXTENSION);
    final File dataFile = new File(storageFilePath + DATA_EXTENSION);

    if (recordsFile.exists() != dataFile.exists()) {
      deleteFiles(storageFilePath);
    }

    FileUtil.createIfDoesntExist(recordsFile);
    FileUtil.createIfDoesntExist(dataFile);

    AbstractRecordsTable recordsTable = null;
    DataTable dataTable;
    try {
      recordsTable = createRecordsTable(pool, recordsFile);
      dataTable = new DataTable(dataFile, pool);
    } catch (IOException e) {
      LOG.info(e.getMessage());
      if (recordsTable != null) {
        recordsTable.dispose();
      }

      boolean deleted = deleteFiles(storageFilePath);
      if (!deleted) {
        throw new IOException("Can't delete caches at: " + storageFilePath);
      }
      if (retryCount >= 5) {
        throw new IOException("Can't create storage at: " + storageFilePath);
      }

      tryInit(storageFilePath, pool, retryCount + 1);
      return;
    }

    myRecordsTable = recordsTable;
    myDataTable = dataTable;
    myPool = pool;

    if (myDataTable.isCompactNecessary()) {
      compact(storageFilePath);
    }
  }
예제 #7
0
  protected void appendBytes(int record, ByteSequence bytes) throws IOException {
    final int delta = bytes.getLength();
    if (delta == 0) return;

    synchronized (myLock) {
      int capacity = myRecordsTable.getCapacity(record);
      int oldSize = myRecordsTable.getSize(record);
      int newSize = oldSize + delta;
      if (newSize > capacity) {
        if (oldSize > 0) {
          final byte[] newbytes = new byte[newSize];
          System.arraycopy(readBytes(record), 0, newbytes, 0, oldSize);
          System.arraycopy(bytes.getBytes(), bytes.getOffset(), newbytes, oldSize, delta);
          writeBytes(record, new ByteSequence(newbytes), false);
        } else {
          writeBytes(record, bytes, false);
        }
      } else {
        long address = myRecordsTable.getAddress(record) + oldSize;
        myDataTable.writeBytes(address, bytes.getBytes(), bytes.getOffset(), bytes.getLength());
        myRecordsTable.setSize(record, newSize);
      }
    }
  }
예제 #8
0
 public void dispose() {
   synchronized (myLock) {
     myRecordsTable.dispose();
     myDataTable.dispose();
   }
 }
예제 #9
0
 protected void doDeleteRecord(int record) throws IOException {
   myDataTable.reclaimSpace(myRecordsTable.getCapacity(record));
   myRecordsTable.deleteRecord(record);
 }
예제 #10
0
 public boolean isDirty() {
   synchronized (myLock) {
     return myDataTable.isDirty() || myRecordsTable.isDirty();
   }
 }
예제 #11
0
 public void force() {
   synchronized (myLock) {
     myDataTable.force();
     myRecordsTable.force();
   }
 }