@Override public DurableDataLog createDurableDataLog(int containerId) { Exceptions.checkNotClosed(this.closed, this); InMemoryDurableDataLog.EntryCollection entries; synchronized (this.persistedData) { entries = this.persistedData.getOrDefault(containerId, null); if (entries == null) { entries = this.maxAppendSize < 0 ? new InMemoryDurableDataLog.EntryCollection() : new InMemoryDurableDataLog.EntryCollection(this.maxAppendSize); this.persistedData.put(containerId, entries); } } return new InMemoryDurableDataLog(entries, this.appendDelayProvider, this.executorService); }
@Override public CompletableFuture<LogAddress> append(ArrayView data, Duration timeout) { ensurePreconditions(); CompletableFuture<LogAddress> result; try { Entry entry = new Entry(data); synchronized (this.entries) { entry.sequenceNumber = this.offset; this.entries.add(entry, clientId); // Only update internals after a successful add. this.offset += entry.data.length; } result = CompletableFuture.completedFuture(new InMemoryLogAddress(entry.sequenceNumber)); } catch (Throwable ex) { return Futures.failedFuture(ex); } Duration delay = this.appendDelayProvider.get(); if (delay.compareTo(Duration.ZERO) <= 0) { // No delay, execute right away. return result; } else { // Schedule the append after the given delay. return result.thenComposeAsync( logAddress -> Futures.delayedFuture(delay, this.executorService) .thenApply(ignored -> logAddress), this.executorService); } }
@Override public void enable() { Exceptions.checkNotClosed(this.closed, this); Preconditions.checkState(!this.initialized, "InMemoryDurableDataLog is initialized; cannot enable."); synchronized (this.entries) { this.entries.enable(); } }
/** * Tests the constructor of InMemoryDurableDataLog. The constructor takes in an EntryCollection and this verifies * that information from a previous instance of an InMemoryDurableDataLog is still accessible. */ @Test(timeout = 5000) public void testConstructor() throws Exception { InMemoryDurableDataLog.EntryCollection entries = new InMemoryDurableDataLog.EntryCollection(); TreeMap<LogAddress, byte[]> writeData; // Create first log and write some data to it. try (DurableDataLog log = new InMemoryDurableDataLog(entries, executorService())) { log.initialize(TIMEOUT); writeData = populate(log, WRITE_COUNT); } // Close the first log, and open a second one, with the same EntryCollection in the constructor. try (DurableDataLog log = new InMemoryDurableDataLog(entries, executorService())) { log.initialize(TIMEOUT); // Verify it contains the same entries. verifyReads(log, writeData); } } }
@Override public void initialize(Duration timeout) throws DataLogInitializationException { long newEpoch = this.entries.acquireLock(this.clientId); synchronized (this.entries) { this.epoch = newEpoch; Entry last = this.entries.getLast(); if (last == null) { this.offset = 0; } else { this.offset = last.sequenceNumber + last.data.length; } } this.initialized = true; }
@Override protected Object createSharedContext() { return new InMemoryDurableDataLog.EntryCollection(); }
@Override public int getMaxAppendLength() { return this.entries.getMaxAppendSize(); }
Iterator<Entry> iterator() { ensureEnabled(); return this.entries.read(Long.MIN_VALUE, Integer.MAX_VALUE); }
@Override public CloseableIterator<ReadItem, DurableDataLogException> getReader() throws DurableDataLogException { ensurePreconditions(); return new ReadResultIterator(this.entries.iterator()); }
void truncate(long upToSequence, String clientId) throws DataLogWriterNotPrimaryException { ensureLock(clientId); ensureEnabled(); this.entries.truncate(upToSequence); }
public void add(Entry entry, String clientId) throws DataLogWriterNotPrimaryException { ensureLock(clientId); ensureEnabled(); this.entries.add(entry); }
void disable(String clientId) throws DataLogWriterNotPrimaryException { ensureLock(clientId); if (!this.enabled.compareAndSet(true, false)) { throw new IllegalStateException("Log already disabled."); } }
@Override public void disable() throws DurableDataLogException { ensurePreconditions(); synchronized (this.entries) { this.entries.disable(this.clientId); } close(); }