private void moveAndClear(LongLongMap from, LongLongMap to) { long[] table = from.table; for (int i = 0; i < table.length; ) { long key = table[i++]; long val = table[i++]; if (key == 0) continue; to.put(key, val); } from.clear(); }
@Override public void commit() { if (isSnapshot) return; if (!tx) { vol.sync(); return; } commitLock.lock(); try { StoreAppend[] snaps = snapshots == null ? STORE_APPENDS_ZERO_ARRAY : snapshots.toArray(STORE_APPENDS_ZERO_ARRAY); for (int i = 0; i < locks.length; i++) { Lock lock = locks[i].writeLock(); lock.lock(); try { long[] m = modified[i].table; for (int j = 0; j < m.length; j += 2) { long recid = m[j]; long recidOffset = recid * 8; if (recidOffset == 0) continue; indexTable.ensureAvailable(recidOffset + 8); long oldVal = indexTable.getLong(recidOffset); indexTable.putLong(recidOffset, m[j + 1]); for (StoreAppend snap : snaps) { LongLongMap m2 = snap.modified[i]; if (m2.get(recid) == 0) { m2.put(recid, oldVal); } } } modified[i].clear(); } finally { lock.unlock(); } } long offset = alloc(1, 1); vol.putUnsignedByte(offset, I_TX_VALID); vol.sync(); } finally { commitLock.unlock(); } }
protected void initOpen() { checkFeaturesBitmap(vol.getLong(HEAD_FEATURES)); // replay log long pos = headerSize; final long volumeSize = vol.length(); long lastValidPos = pos; long highestRecid2 = RECID_LAST_RESERVED; LongLongMap commitData = tx ? new LongLongMap() : null; try { while (true) { lastValidPos = pos; if (pos >= volumeSize) break; final long instPos = pos; final int inst = vol.getUnsignedByte(pos++); if (inst == I_INSERT || inst == I_UPDATE) { long recid = vol.getPackedLong(pos); pos += recid >>> 60; recid = longParityGet(recid & DataIO.PACK_LONG_RESULT_MASK); highestRecid2 = Math.max(highestRecid2, recid); commitData.put(recid, instPos); // skip rest of the record long size = vol.getPackedLong(pos); long dataLen = longParityGet(size & DataIO.PACK_LONG_RESULT_MASK) - 1; dataLen = Math.max(0, dataLen); pos = pos + (size >>> 60) + dataLen; } else if (inst == I_DELETE) { long recid = vol.getPackedLong(pos); pos += recid >>> 60; recid = longParityGet(recid & DataIO.PACK_LONG_RESULT_MASK); highestRecid2 = Math.max(highestRecid2, recid); commitData.put(recid, -1); } else if (inst == I_DELETE) { long recid = vol.getPackedLong(pos); pos += recid >>> 60; recid = longParityGet(recid & DataIO.PACK_LONG_RESULT_MASK); highestRecid2 = Math.max(highestRecid2, recid); commitData.put(recid, -2); } else if (inst == I_SKIP_SINGLE_BYTE) { // do nothing, just skip single byte } else if (inst == I_SKIP_MULTI_BYTE) { // read size and skip it // skip rest of the record long size = vol.getPackedLong(pos); pos += (size >>> 60) + longParityGet(size & DataIO.PACK_LONG_RESULT_MASK); } else if (inst == I_TX_VALID) { if (tx) { // apply changes from commitData to indexTable for (int i = 0; i < commitData.table.length; i += 2) { long recidOffset = commitData.table[i] * 8; if (recidOffset == 0) continue; indexTable.ensureAvailable(recidOffset + 8); indexTable.putLong(recidOffset, commitData.table[i + 1]); } commitData.clear(); } } else if (inst == I_TX_ROLLBACK) { if (tx) { commitData.clear(); } } else if (inst == 0) { // rollback last changes if that is necessary if (tx) { // rollback changes in index table since last valid tx commitData.clear(); } break; } else { // TODO log here? LOG.warning("Unknown instruction " + inst); break; } } } catch (RuntimeException e) { // log replay finished // TODO log here? LOG.log(Level.WARNING, "Log replay finished", e); if (tx) { // rollback changes in index table since last valid tx commitData.clear(); } } eof = lastValidPos; highestRecid.set(highestRecid2); }
@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(); } }