nstream.persist.kv.state.MapState Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of nstream-persist-kv Show documentation
Show all versions of nstream-persist-kv Show documentation
Adapter for persistence implementations based on key-value stores
// 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.ArrayList;
import java.util.Comparator;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import nstream.persist.api.PersistenceException;
import nstream.persist.api.cache.MapBackingStore;
import swim.api.store.StoreException;
import swim.collections.BTree;
import swim.recon.Recon;
import swim.structure.Value;
import swim.util.OrderedMapCursor;
/**
* Map backing store that notifies the {@link StoreState} of changes to be committed.
*/
public class MapState extends StateBase implements MapBackingStore {
private static final AtomicReferenceFieldUpdater CONTENTS = AtomicReferenceFieldUpdater.newUpdater(MapState.class, MapStateInner.class, "contents");
private final long id;
private final StoreState owner;
private volatile MapStateInner contents;
/**
* @param owner The store state that owns this map store.
* @param id The database ID of the map lane.
* @param contents The initial contents of the map state.
*/
public MapState(StoreState owner, long id, final BTree contents) {
this.owner = owner;
this.id = id;
this.contents = new MapStateInner(contents);
}
@Override
public Value put(Value key, Value newValue) {
key = Objects.requireNonNull(key).commit();
newValue = Objects.requireNonNullElseGet(newValue, Value::extant).commit();
Value prev;
MapStateInner oldInner, newInner;
do {
oldInner = CONTENTS.get(this);
prev = oldInner.getMap().get(key);
newInner = oldInner.updated(key, newValue);
} while (!CONTENTS.compareAndSet(this, oldInner, newInner));
if (!this.isTransient() && newInner != oldInner) {
try {
this.owner.mapKeyUpdated(this.id, newInner.getEpoch(), key, Recon.sizeOf(newValue));
} catch (PersistenceException e) {
throw new StoreException(e);
}
}
return prev;
}
@Override
public Value remove(Object key) {
if (key instanceof Value) {
final Value typedKey = ((Value) key).commit();
Value prev;
MapStateInner oldInner, newInner;
do {
oldInner = CONTENTS.get(this);
prev = oldInner.getMap().get(typedKey);
if (prev == null) {
return null;
}
newInner = oldInner.removed(typedKey);
} while (!CONTENTS.compareAndSet(this, oldInner, newInner));
if (!this.isTransient() && newInner != oldInner) {
try {
this.owner.mapKeyUpdated(this.id, newInner.getEpoch(), typedKey, 0);
} catch (PersistenceException e) {
throw new StoreException(e);
}
}
return prev;
} else {
return null;
}
}
@Override
public void clear() {
MapStateInner oldInner, newInner;
do {
oldInner = CONTENTS.get(this);
newInner = oldInner.cleared();
} while (!CONTENTS.compareAndSet(this, oldInner, newInner));
if (!this.isTransient()) {
try {
this.owner.mapCleared(this.id, newInner.getEpoch());
} catch (PersistenceException e) {
throw new StoreException(e);
}
}
}
public void takePrefix(int n) {
MapStateInner oldInner, newInner;
final ArrayList removed = new ArrayList<>(n);
do {
removed.clear();
oldInner = CONTENTS.get(this);
newInner = oldInner.taken(n, removed);
} while (!CONTENTS.compareAndSet(this, oldInner, newInner));
if (!this.isTransient()) {
try {
for (Value key : removed) {
this.owner.mapKeyUpdated(this.id, newInner.getEpoch(), key, 0);
}
} catch (PersistenceException e) {
throw new StoreException(e);
}
}
}
public void dropPrefix(int n) {
MapStateInner oldInner, newInner;
final ArrayList removed = new ArrayList<>(n);
do {
removed.clear();
oldInner = CONTENTS.get(this);
newInner = oldInner.dropped(n, removed);
} while (!CONTENTS.compareAndSet(this, oldInner, newInner));
if (!this.isTransient()) {
try {
for (Value key : removed) {
this.owner.mapKeyUpdated(this.id, newInner.getEpoch(), key, 0);
}
} catch (PersistenceException e) {
throw new StoreException(e);
}
}
}
@Override
public boolean isEmpty() {
return CONTENTS.get(this).getMap().isEmpty();
}
@Override
public int size() {
return CONTENTS.get(this).getMap().size();
}
@Override
public boolean containsKey(Object key) {
return CONTENTS.get(this).getMap().containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return CONTENTS.get(this).getMap().containsValue(value);
}
@Override
public int indexOf(Object key) {
return CONTENTS.get(this).getMap().indexOf(key);
}
@Override
public Value get(Object key) {
return CONTENTS.get(this).getMap().get(key);
}
@Override
public Entry getEntry(Object key) {
return CONTENTS.get(this).getMap().getEntry(key);
}
@Override
public Entry getIndex(int index) {
return CONTENTS.get(this).getMap().getIndex(index);
}
@Override
public Entry firstEntry() {
return CONTENTS.get(this).getMap().firstEntry();
}
@Override
public Value firstKey() {
return CONTENTS.get(this).getMap().firstKey();
}
@Override
public Value firstValue() {
return CONTENTS.get(this).getMap().firstValue();
}
@Override
public Entry lastEntry() {
return CONTENTS.get(this).getMap().lastEntry();
}
@Override
public Value lastKey() {
return CONTENTS.get(this).getMap().lastKey();
}
@Override
public Value lastValue() {
return CONTENTS.get(this).getMap().lastValue();
}
@Override
public Entry nextEntry(Value key) {
return CONTENTS.get(this).getMap().nextEntry(key);
}
@Override
public Value nextKey(Value key) {
return CONTENTS.get(this).getMap().nextKey(key);
}
@Override
public Value nextValue(Value key) {
return CONTENTS.get(this).getMap().nextValue(key);
}
@Override
public Entry previousEntry(Value key) {
return CONTENTS.get(this).getMap().previousEntry(key);
}
@Override
public Value previousKey(Value key) {
return CONTENTS.get(this).getMap().previousKey(key);
}
@Override
public Value previousValue(Value key) {
return CONTENTS.get(this).getMap().previousValue(key);
}
@SuppressWarnings("NullableProblems")
@Override
public OrderedMapCursor iterator() {
return CONTENTS.get(this).getMap().iterator();
}
@Override
public Comparator super Value> comparator() {
return CONTENTS.get(this).getMap().comparator();
}
public BTree snapshot() {
return CONTENTS.get(this).getMap();
}
@Override
public void close() {
}
}