@Test
  public void open_ignores_rollback() {
    File f = TT.tempDbFile();
    WriteAheadLog wal = new WriteAheadLog(f.getPath());
    wal.walPutLong(1L, 11L);
    wal.commit();
    wal.walPutLong(2L, 33L);
    wal.rollback();
    wal.walPutLong(3L, 33L);
    wal.commit();
    wal.seal();
    wal.close();

    wal = new WriteAheadLog(f.getPath());
    wal.open(
        new WALSequence(
            new Object[] {WALSequence.beforeReplayStart},
            new Object[] {WALSequence.writeLong, 1L, 11L},
            new Object[] {WALSequence.commit},
            // 2L is ignored, rollback section is skipped on hard replay
            new Object[] {WALSequence.writeLong, 3L, 33L},
            new Object[] {WALSequence.commit}));
    wal.destroyWalFiles();
    wal.close();

    f.delete();
  }
Beispiel #2
0
  @Override
  public void close() {
    commitLock.lock();
    try {

      if (closed) {
        return;
      }

      if (hasUncommitedData()) {
        LOG.warning("Closing storage with uncommited data, this data will be discarded.");
      }

      headVol.putData(0, headVolBackup, 0, headVolBackup.length);

      if (!readonly) {
        replaySoft();
        wal.destroyWalFiles();
      }
      wal.close();

      vol.close();
      vol = null;

      headVol.close();
      headVol = null;
      headVolBackup = null;

      uncommittedStackPages.clear();

      if (caches != null) {
        for (Cache c : caches) {
          c.close();
        }
        Arrays.fill(caches, null);
      }
      if (fileLockHeartbeat != null) {
        fileLockHeartbeat.unlock();
        fileLockHeartbeat = null;
      }
      closed = true;
    } finally {
      commitLock.unlock();
    }
  }
  @Test
  public void overflow_record() {
    File f = TT.tempDbFile();
    f.delete();
    File f0 = new File(f.getPath() + ".wal.0");
    File f1 = new File(f.getPath() + ".wal.1");
    WriteAheadLog wal = new WriteAheadLog(f.getPath());
    wal.open(WriteAheadLog.NOREPLAY);

    long lastPos = 0;
    while (!f1.exists()) {
      lastPos = wal.fileOffset;
      wal.walPutRecord(111L, new byte[100], 0, 100);
      assertTrue(f0.exists());
    }
    assertTrue(WriteAheadLog.MAX_FILE_SIZE - 1000 < lastPos);
    assertTrue(WriteAheadLog.MAX_FILE_SIZE + 120 > lastPos);
    wal.destroyWalFiles();
  }
Beispiel #4
0
  @Override
  public void commit() {
    commitLock.lock();
    try {
      // flush write caches into write ahead log
      flushWriteCache();

      // move uncommited data to committed
      for (int segment = 0; segment < locks.length; segment++) {
        locks[segment].writeLock().lock();
        try {
          // dump index vals into WAL
          long[] table = uncommittedIndexTable[segment].table;
          for (int i = 0; i < table.length; ) {
            long offset = table[i++];
            long val = table[i++];
            if (offset == 0) continue;
            wal.walPutLong(offset, val);
          }

          moveAndClear(uncommittedIndexTable[segment], committedIndexTable[segment]);
          moveAndClear(uncommittedDataLongs[segment], committedDataLongs[segment]);

        } finally {
          locks[segment].writeLock().unlock();
        }
      }

      structuralLock.lock();
      try {
        // flush modified Long Stack pages into WAL
        long[] set = uncommittedStackPages.set;
        longStackPagesLoop:
        for (int i = 0; i < set.length; i++) {
          long offset = set[i];
          if (offset == 0) continue longStackPagesLoop;
          byte[] val = (byte[]) uncommittedStackPages.values[i];

          if (val == LONG_STACK_PAGE_TOMBSTONE) committedPageLongStack.put(offset, -1);
          else {
            if (CC.ASSERT) assertLongStackPage(offset, val);

            long walPointer = wal.walPutByteArray(offset, val, 0, val.length);
            committedPageLongStack.put(offset, walPointer);
          }
        }
        uncommittedStackPages.clear();

        // update checksum
        headVol.putInt(HEAD_CHECKSUM, headChecksum(headVol));
        // take backup of headVol
        headVol.getData(0, headVolBackup, 0, headVolBackup.length);
        wal.walPutByteArray(0, headVolBackup, 0, headVolBackup.length);
        wal.commit();
        wal.seal();
        replaySoft();
        realVol.sync();
        wal.destroyWalFiles();
      } finally {
        structuralLock.unlock();
      }
    } finally {
      commitLock.unlock();
    }
  }
Beispiel #5
0
  @Override
  public void initOpen() {
    // TODO disable readonly feature for this store

    realVol = vol;

    if (readonly && !Volume.isEmptyFile(fileName + ".wal.0"))
      throw new DBException.WrongConfig(
          "There is dirty WAL file, but storage is read-only. Can not replay file");

    wal.open(
        new WriteAheadLog.WALReplay() {

          @Override
          public void beforeReplayStart() {}

          @Override
          public void writeLong(long offset, long value) {
            if (CC.ASSERT && offset % 8 != 0) throw new AssertionError();
            realVol.ensureAvailable(Fun.roundUp(offset + 8, StoreDirect.PAGE_SIZE));
            realVol.putLong(offset, value);
          }

          @Override
          public void writeRecord(long recid, long walId, Volume vol, long volOffset, int length) {
            throw new DBException.DataCorruption();
          }

          @Override
          public void writeByteArray(
              long offset, long walId, Volume vol, long volOffset, int length) {
            if (CC.ASSERT && offset % 8 != 0) throw new AssertionError();
            realVol.ensureAvailable(Fun.roundUp(offset + length, StoreDirect.PAGE_SIZE));
            vol.transferInto(volOffset, realVol, offset, length);
          }

          @Override
          public void beforeDestroyWAL() {}

          @Override
          public void commit() {}

          @Override
          public void rollback() {
            throw new DBException.DataCorruption();
          }

          @Override
          public void writeTombstone(long recid) {
            throw new DBException.DataCorruption();
          }

          @Override
          public void writePreallocate(long recid) {
            throw new DBException.DataCorruption();
          }
        });
    realVol.sync();
    wal.destroyWalFiles();

    initOpenPost();

    // TODO reenable this assertion
    //        if(CC.PARANOID)
    //            storeCheck();
  }