@Override public void install(SnapshotReader reader) { List<ResourceHolder> resources = new ArrayList<>(this.resources.values()); Collections.sort(resources, (r1, r2) -> (int)(r1.id - r2.id)); for (ResourceHolder resource : resources) { if (resource.stateMachine instanceof Snapshottable) { ((Snapshottable) resource.stateMachine).install(reader); } } }
@Override public void snapshot(SnapshotWriter writer) { List<ResourceHolder> resources = new ArrayList<>(this.resources.values()); Collections.sort(resources, (r1, r2) -> (int) (r1.id - r2.id)); for (ResourceHolder resource : resources) { if (resource.stateMachine instanceof Snapshottable) { ((Snapshottable) resource.stateMachine).snapshot(writer); } } }
@Override public void snapshot(SnapshotWriter writer) { List<ResourceHolder> resources = new ArrayList<>(this.resources.values()); Collections.sort(resources, (r1, r2) -> (int) (r1.id - r2.id)); for (ResourceHolder resource : resources) { if (resource.stateMachine instanceof Snapshottable) { ((Snapshottable) resource.stateMachine).snapshot(writer); } } }
@Override public void install(SnapshotReader reader) { List<ResourceHolder> resources = new ArrayList<>(this.resources.values()); Collections.sort(resources, (r1, r2) -> (int)(r1.id - r2.id)); for (ResourceHolder resource : resources) { if (resource.stateMachine instanceof Snapshottable) { ((Snapshottable) resource.stateMachine).install(reader); } } }
/** * Takes a snapshot of the state machine state if necessary. * <p> * Snapshots of the state machine are taken only once the log becomes compactable. This means snapshots * are largely dependent on the storage configuration and ensures that snapshots are not taken more * frequently than will benefit log compaction. */ private void takeSnapshot() { state.checkThread(); // If no snapshot has been taken, take a snapshot and hold it in memory until the complete // index has met the snapshot index. Note that this will be executed in the state machine thread. // Snapshots are only taken of the state machine when the log becomes compactable. If the log compactor's // compactIndex is greater than the last snapshot index and the lastApplied index is greater than the // last snapshot index, take the snapshot. Snapshot currentSnapshot = state.getSnapshotStore().currentSnapshot(); if (pendingSnapshot == null && stateMachine instanceof Snapshottable && (currentSnapshot == null || (log.compactor().compactIndex() > currentSnapshot.index() && lastApplied > currentSnapshot.index()))) { pendingSnapshot = state.getSnapshotStore().createSnapshot(lastApplied); // Write the snapshot data. Note that we don't complete the snapshot here since the completion // of a snapshot is predicated on session events being received by clients up to the snapshot index. LOGGER.info("{} - Taking snapshot {}", state.getCluster().member().address(), pendingSnapshot.index()); executor.executor().execute(() -> { synchronized (pendingSnapshot) { try (SnapshotWriter writer = pendingSnapshot.writer()) { ((Snapshottable) stateMachine).snapshot(writer); } } }); } }
/** * Installs a snapshot of the state machine state if necessary. * <p> * Snapshots are installed only if there's a local snapshot stored with a version equal to the * last applied index. */ private void installSnapshot() { // If the last stored snapshot has not yet been installed and its index matches the last applied state // machine index, install the snapshot. This requires that the state machine see all indexes sequentially // even for entries that have been compacted from the log. Snapshot currentSnapshot = state.getSnapshotStore().currentSnapshot(); if (currentSnapshot != null && currentSnapshot.index() > log.compactor().snapshotIndex() && currentSnapshot.index() == lastApplied && stateMachine instanceof Snapshottable) { // Install the snapshot in the state machine thread. Multiple threads can access snapshots, so we // synchronize on the snapshot object. In practice, this probably isn't even necessary and could prove // to be an expensive operation. Snapshots can be read concurrently with separate SnapshotReaders since // memory snapshots are copied to the reader and file snapshots open a separate FileBuffer for each reader. LOGGER.info("{} - Installing snapshot {}", state.getCluster().member().address(), currentSnapshot.index()); executor.executor().execute(() -> { synchronized (currentSnapshot) { try (SnapshotReader reader = currentSnapshot.reader()) { ((Snapshottable) stateMachine).install(reader); } } }); // Once a snapshot has been applied, snapshot dependent entries can be cleaned from the log. log.compactor().snapshotIndex(currentSnapshot.index()); } }
/** * Takes a snapshot of the state machine state if necessary. * <p> * Snapshots of the state machine are taken only once the log becomes compactable. This means snapshots * are largely dependent on the storage configuration and ensures that snapshots are not taken more * frequently than will benefit log compaction. */ private void takeSnapshot() { state.checkThread(); // If no snapshot has been taken, take a snapshot and hold it in memory until the complete // index has met the snapshot index. Note that this will be executed in the state machine thread. // Snapshots are only taken of the state machine when the log becomes compactable. If the log compactor's // compactIndex is greater than the last snapshot index and the lastApplied index is greater than the // last snapshot index, take the snapshot. Snapshot currentSnapshot = state.getSnapshotStore().currentSnapshot(); if (pendingSnapshot == null && stateMachine instanceof Snapshottable && (currentSnapshot == null || (log.compactor().compactIndex() > currentSnapshot.index() && lastApplied > currentSnapshot.index()))) { pendingSnapshot = state.getSnapshotStore().createSnapshot(lastApplied); // Write the snapshot data. Note that we don't complete the snapshot here since the completion // of a snapshot is predicated on session events being received by clients up to the snapshot index. LOGGER.info("{} - Taking snapshot {}", state.getCluster().member().address(), pendingSnapshot.index()); executor.executor().execute(() -> { synchronized (pendingSnapshot) { try (SnapshotWriter writer = pendingSnapshot.writer()) { ((Snapshottable) stateMachine).snapshot(writer); } } }); } }
/** * Installs a snapshot of the state machine state if necessary. * <p> * Snapshots are installed only if there's a local snapshot stored with a version equal to the * last applied index. */ private void installSnapshot() { state.checkThread(); // If the last stored snapshot has not yet been installed and its index matches the last applied state // machine index, install the snapshot. This requires that the state machine see all indexes sequentially // even for entries that have been compacted from the log. Snapshot currentSnapshot = state.getSnapshotStore().currentSnapshot(); if (currentSnapshot != null && currentSnapshot.index() > log.compactor().snapshotIndex() && currentSnapshot.index() == lastApplied && stateMachine instanceof Snapshottable) { // Install the snapshot in the state machine thread. Multiple threads can access snapshots, so we // synchronize on the snapshot object. In practice, this probably isn't even necessary and could prove // to be an expensive operation. Snapshots can be read concurrently with separate SnapshotReaders since // memory snapshots are copied to the reader and file snapshots open a separate FileBuffer for each reader. LOGGER.info("{} - Installing snapshot {}", state.getCluster().member().address(), currentSnapshot.index()); executor.executor().execute(() -> { synchronized (currentSnapshot) { try (SnapshotReader reader = currentSnapshot.reader()) { ((Snapshottable) stateMachine).install(reader); } } }); // Once a snapshot has been applied, snapshot dependent entries can be cleaned from the log. log.compactor().snapshotIndex(currentSnapshot.index()); } }
/** * Takes a snapshot of the state machine state if necessary. * <p> * Snapshots of the state machine are taken only once the log becomes compactable. This means snapshots * are largely dependent on the storage configuration and ensures that snapshots are not taken more * frequently than will benefit log compaction. */ private void takeSnapshot() { // If no snapshot has been taken, take a snapshot and hold it in memory until the complete // index has met the snapshot index. Note that this will be executed in the state machine thread. // Snapshots are only taken of the state machine when the log becomes compactable. If the log compactor's // compactIndex is greater than the last snapshot index and the lastApplied index is greater than the // last snapshot index, take the snapshot. Snapshot currentSnapshot = state.getSnapshotStore().currentSnapshot(); if (pendingSnapshot == null && stateMachine instanceof Snapshottable && (currentSnapshot == null || (log.compactor().compactIndex() > currentSnapshot.index() && lastApplied > currentSnapshot.index()))) { pendingSnapshot = state.getSnapshotStore().createSnapshot(lastApplied); // Write the snapshot data. Note that we don't complete the snapshot here since the completion // of a snapshot is predicated on session events being received by clients up to the snapshot index. LOGGER.info("{} - Taking snapshot {}", state.getCluster().member().address(), pendingSnapshot.index()); synchronized (pendingSnapshot) { try (SnapshotWriter writer = pendingSnapshot.writer()) { ((Snapshottable) stateMachine).snapshot(writer); } } } }
/** * Installs a snapshot of the state machine state if necessary. * <p> * Snapshots are installed only if there's a local snapshot stored with a version equal to the * last applied index. */ private void installSnapshot() { state.checkThread(); // If the last stored snapshot has not yet been installed and its index matches the last applied state // machine index, install the snapshot. This requires that the state machine see all indexes sequentially // even for entries that have been compacted from the log. Snapshot currentSnapshot = state.getSnapshotStore().currentSnapshot(); if (currentSnapshot != null && currentSnapshot.index() > log.compactor().snapshotIndex() && currentSnapshot.index() == lastApplied && stateMachine instanceof Snapshottable) { // Install the snapshot in the state machine thread. Multiple threads can access snapshots, so we // synchronize on the snapshot object. In practice, this probably isn't even necessary and could prove // to be an expensive operation. Snapshots can be read concurrently with separate SnapshotReaders since // memory snapshots are copied to the reader and file snapshots open a separate FileBuffer for each reader. LOGGER.info("{} - Installing snapshot {}", state.getCluster().member().address(), currentSnapshot.index()); executor.executor().execute(() -> { synchronized (currentSnapshot) { try (SnapshotReader reader = currentSnapshot.reader()) { ((Snapshottable) stateMachine).install(reader); } } }); // Once a snapshot has been applied, snapshot dependent entries can be cleaned from the log. log.compactor().snapshotIndex(currentSnapshot.index()); } }