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

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

There is a newer version: 4.12.20
Show newest version
// 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 comparator() {
    return CONTENTS.get(this).getMap().comparator();
  }

  public BTree snapshot() {
    return CONTENTS.get(this).getMap();
  }

  @Override
  public void close() {

  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy