All Downloads are FREE. Search and download functionalities are using the official Maven repository.

nstream.persist.kv.state.MapChangeset Maven / Gradle / Ivy

// Copyright 2015-2024 Nstream, inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package nstream.persist.kv.state;

import java.util.Collection;
import java.util.Objects;
import swim.collections.HashTrieMap;
import swim.recon.Recon;
import swim.structure.Value;

/**
 * Records the changes made to a map lane since its most recent commit. The state of a map lane has a monotonic epoch
 * counter that is incremented each time the map is cleared. The changeset keeps track of this epoch and will
 * disregard changes that were made in a previous epoch (as they can be guaranteed to be irrelevant).
 * 

* Change-sets are immutable and all methods will produce a new instance. */ public final class MapChangeset { // The current monotonically increasing epoch of the map lane. private final long currentEpoch; // Whether the map has been cleared (this will be applied to the data store before any updates). private final boolean cleared; // The total size of the change-set in bytes. private final long totalSize; // Keys that have been updated. private final HashTrieMap keys; private MapChangeset(long currentEpoch, boolean cleared, HashTrieMap keys, long totalSize) { this.currentEpoch = currentEpoch; this.cleared = cleared; this.keys = keys; this.totalSize = totalSize; } public MapChangeset(long currentEpoch) { this.currentEpoch = currentEpoch; this.cleared = false; this.keys = HashTrieMap.empty(); this.totalSize = 0; } /** * Indicate that an entry in the map has been updated. * * @param epoch The epoch of the update. * @param key The key of the modified entry. * @param valueSize The size of the value ({@code 0} for a removal). * @return The updated changeset. */ public MapChangeset added(long epoch, Value key, long valueSize) { if (epoch < this.currentEpoch) { return this; } final var oldSize = this.keys.get(key); final long delta; if (oldSize == null) { delta = Recon.sizeOf(key) + valueSize; } else { if (valueSize == oldSize) { return this; } delta = valueSize - oldSize; } return new MapChangeset(this.currentEpoch, this.cleared, this.keys.updated(key, valueSize), this.totalSize + delta); } /** * Indicate that the map state has been cleared. * * @param epoch The epoch of the change. * @return The updated change-set. */ public MapChangeset cleared(long epoch) { if (epoch < this.currentEpoch) { return this; } else { return new MapChangeset(epoch, true, HashTrieMap.empty(), 0); } } public boolean isCleared() { return this.cleared; } public Collection keys() { return this.keys.keySet(); } /** * @return The total size of all changes in this change-set in bytes. */ public long getCommitSize() { return this.totalSize; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } final MapChangeset that = (MapChangeset) o; return this.currentEpoch == that.currentEpoch && this.cleared == that.cleared && this.totalSize == that.totalSize && Objects.equals(this.keys, that.keys); } @Override public int hashCode() { return Objects.hash(this.currentEpoch, this.cleared, this.totalSize, this.keys); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy