@Override public CloseableKVStore mutableSnapshot() { // Build copy CloseableKVStore kvstore; if (this.kvdb.kv instanceof NavigableMapKVStore) { final NavigableMapKVStore kv; synchronized (this.kvdb) { kv = ((NavigableMapKVStore)this.kvdb.kv).clone(); } kvstore = new CloseableForwardingKVStore(kv.clone()); } else if (this.kvdb.kv instanceof AtomicKVStore) { final AtomicKVStore kv = (AtomicKVStore)this.kvdb.kv; final CloseableKVStore snapshot = kv.snapshot(); final MutableView view = new MutableView(snapshot); view.disableReadTracking(); kvstore = new CloseableForwardingKVStore(view, snapshot); } else { throw new UnsupportedOperationException("underlying KVStore " + this.kvdb.kv.getClass().getSimpleName() + " is not an AtomicKVStore"); } // Apply mutations synchronized (this.kvdb) { for (Mutation mutation : this.mutations) mutation.apply(kvstore); } // Done return kvstore; }
MostRecentView(final RaftKVDatabase raft, final long maxIndex) { // Sanity check assert raft != null; assert Thread.holdsLock(raft); assert maxIndex >= 0; // Grab a snapshot of the key/value store this.snapshot = raft.kv.snapshot(); // Create a view of just the state machine keys and values and successively layer unapplied log entries up to maxIndex KVStore kview = PrefixKVStore.create(snapshot, raft.getStateMachinePrefix()); this.config = new HashMap<>(raft.log.getLastAppliedConfig()); long viewIndex = raft.log.getLastAppliedIndex(); long viewTerm = raft.log.getLastAppliedTerm(); for (LogEntry logEntry : raft.log.getUnapplied()) { if (logEntry.getIndex() > maxIndex) break; final Writes writes = logEntry.getWrites(); if (!writes.isEmpty()) kview = new MutableView(kview, null, writes); logEntry.applyConfigChange(this.config); viewIndex = logEntry.getIndex(); viewTerm = logEntry.getTerm(); } // Finalize this.view = new MutableView(kview); this.term = viewTerm; this.index = viewIndex; }