private WriteBatchImpl readWriteBatch(SliceInput record, int updateSize) throws IOException { WriteBatchImpl writeBatch = new WriteBatchImpl(); int entries = 0; while (record.isReadable()) { entries++; ValueType valueType = ValueType.getValueTypeByPersistentId(record.readByte()); if (valueType == VALUE) { Slice key = readLengthPrefixedBytes(record); Slice value = readLengthPrefixedBytes(record); writeBatch.put(key, value); } else if (valueType == DELETION) { Slice key = readLengthPrefixedBytes(record); writeBatch.delete(key); } else { throw new IllegalStateException("Unexpected value type " + valueType); } } if (entries != updateSize) { throw new IOException( String.format( "Expected %d entries in log record but found %s entries", updateSize, entries)); } return writeBatch; }
private long recoverLogFile(long fileNumber, VersionEdit edit) throws IOException { Preconditions.checkState(mutex.isHeldByCurrentThread()); File file = new File(databaseDir, Filename.logFileName(fileNumber)); FileChannel channel = new FileInputStream(file).getChannel(); try { LogMonitor logMonitor = LogMonitors.logMonitor(); LogReader logReader = new LogReader(channel, logMonitor, true, 0); // Log(options_.info_log, "Recovering log #%llu", (unsigned long long) log_number); // Read all the records and add to a memtable long maxSequence = 0; MemTable memTable = null; for (Slice record = logReader.readRecord(); record != null; record = logReader.readRecord()) { SliceInput sliceInput = record.input(); // read header if (sliceInput.available() < 12) { logMonitor.corruption(sliceInput.available(), "log record too small"); continue; } long sequenceBegin = sliceInput.readLong(); int updateSize = sliceInput.readInt(); // read entries WriteBatchImpl writeBatch = readWriteBatch(sliceInput, updateSize); // apply entries to memTable if (memTable == null) { memTable = new MemTable(internalKeyComparator); } writeBatch.forEach(new InsertIntoHandler(memTable, sequenceBegin)); // update the maxSequence long lastSequence = sequenceBegin + updateSize - 1; if (lastSequence > maxSequence) { maxSequence = lastSequence; } // flush mem table if necessary if (memTable.approximateMemoryUsage() > options.writeBufferSize()) { writeLevel0Table(memTable, edit, null); memTable = null; } } // flush mem table if (memTable != null && !memTable.isEmpty()) { writeLevel0Table(memTable, edit, null); } return maxSequence; } finally { channel.close(); } }
private Slice writeWriteBatch(WriteBatchImpl updates, long sequenceBegin) { Slice record = Slices.allocate(SIZE_OF_LONG + SIZE_OF_INT + updates.getApproximateSize()); final SliceOutput sliceOutput = record.output(); sliceOutput.writeLong(sequenceBegin); sliceOutput.writeInt(updates.size()); updates.forEach( new Handler() { @Override public void put(Slice key, Slice value) { sliceOutput.writeByte(VALUE.getPersistentId()); writeLengthPrefixedBytes(sliceOutput, key); writeLengthPrefixedBytes(sliceOutput, value); } @Override public void delete(Slice key) { sliceOutput.writeByte(DELETION.getPersistentId()); writeLengthPrefixedBytes(sliceOutput, key); } }); return record.slice(0, sliceOutput.size()); }
public Snapshot writeInternal(WriteBatchImpl updates, WriteOptions options) throws DBException { checkBackgroundException(); mutex.lock(); try { long sequenceEnd; if (updates.size() != 0) { makeRoomForWrite(false); // Get sequence numbers for this change set final long sequenceBegin = versions.getLastSequence() + 1; sequenceEnd = sequenceBegin + updates.size() - 1; // Reserve this sequence in the version set versions.setLastSequence(sequenceEnd); // Log write Slice record = writeWriteBatch(updates, sequenceBegin); try { log.addRecord(record, options.sync()); } catch (IOException e) { throw Throwables.propagate(e); } // Update memtable updates.forEach(new InsertIntoHandler(memTable, sequenceBegin)); } else { sequenceEnd = versions.getLastSequence(); } if (options.snapshot()) { return new SnapshotImpl(versions.getCurrent(), sequenceEnd); } else { return null; } } finally { mutex.unlock(); } }