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(); }
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); }
protected void replaySoft() { if (CC.ASSERT && !commitLock.isHeldByCurrentThread()) throw new AssertionError(); LongList written = CC.PARANOID ? new LongList() : null; for (int lockPos = 0; lockPos < locks.length; lockPos++) { locks[lockPos].writeLock().lock(); try { // update index table long[] table = committedIndexTable[lockPos].table; indexValLoop: for (int pos = 0; pos < table.length; ) { long recidOffset = table[pos++]; long val = table[pos++]; if (recidOffset == 0 || val == -1) continue indexValLoop; realVol.ensureAvailable(Fun.roundUp(recidOffset + 8, StoreDirect.PAGE_SIZE)); realVol.putLong(recidOffset, val); if (CC.PARANOID) { // check this is index page if (!Fun.arrayContains(indexPages, Fun.roundDown(recidOffset, PAGE_SIZE))) { throw new AssertionError("not index page"); } } } committedIndexTable[lockPos].clear(); // write data table = committedDataLongs[lockPos].table; dataLoop: for (int pos = 0; pos < table.length; ) { long volOffset = table[pos++]; long walPointer = table[pos++]; if (volOffset == 0 || walPointer == -1) continue dataLoop; byte[] b = wal.walGetByteArray2(walPointer); if (CC.ASSERT) assertRecord(volOffset, b); realVol.ensureAvailable(Fun.roundUp(volOffset + b.length, StoreDirect.PAGE_SIZE)); realVol.putData(volOffset, b, 0, b.length); if (CC.ASSERT && b.length > MAX_REC_SIZE) throw new AssertionError(); if (CC.PARANOID) written.add((volOffset << 16) | b.length); } committedDataLongs[lockPos].clear(); } finally { locks[lockPos].writeLock().unlock(); } } structuralLock.lock(); try { // flush modified Long Stack pages dataLoop: for (int pos = 0; pos < committedPageLongStack.table.length; ) { long volOffset = committedPageLongStack.table[pos++]; long walPointer = committedPageLongStack.table[pos++]; if (volOffset == 0 || walPointer == -1) continue dataLoop; byte[] b = wal.walGetByteArray2(walPointer); if (CC.ASSERT) assertLongStackPage(volOffset, b); realVol.ensureAvailable(Fun.roundUp(volOffset + b.length, StoreDirect.PAGE_SIZE)); realVol.putData(volOffset, b, 0, b.length); if (CC.PARANOID) written.add((volOffset << 16) | b.length); } committedPageLongStack.clear(); if (CC.PARANOID) { byte[] headVolBuf = new byte[headVolBackup.length]; headVol.getData(0, headVolBuf, 0, headVolBuf.length); if (!Arrays.equals(headVolBuf, headVolBackup)) throw new AssertionError(); } // update page header realVol.putData(0, headVolBackup, 0, headVolBackup.length); } finally { structuralLock.unlock(); } if (CC.PARANOID) { // check for overlaps long[] w = Arrays.copyOf(written.array, written.size); Arrays.sort(w); for (int i = 0; i < w.length - 1; i++) { long offset1 = w[i] >>> 16; long size1 = w[i] & 0xFF; long offset2 = w[i + 1] >>> 16; long size2 = w[i + 1] & 0xFF; if (offset1 + size1 > offset2) { throw new AssertionError( "write overlap conflict at: " + offset1 + " + " + size1 + " > " + offset2 + " (" + size2 + ")"); } } } }