/* * Copyright 2016 higherfrequencytrading.com * * 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 net.openhft.chronicle.engine.map; import net.openhft.chronicle.bytes.BytesStore; import net.openhft.chronicle.engine.api.EngineReplication; import net.openhft.chronicle.engine.api.map.KeyValueStore; import net.openhft.chronicle.engine.api.map.MapEvent; import net.openhft.chronicle.engine.api.pubsub.InvalidSubscriberException; import net.openhft.chronicle.engine.api.pubsub.SubscriptionConsumer; import net.openhft.chronicle.engine.api.tree.Asset; import net.openhft.chronicle.wire.Marshallable; import net.openhft.chronicle.wire.ReadMarshallable; import net.openhft.chronicle.wire.TextWire; import net.openhft.chronicle.wire.Wire; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.function.Function; import java.util.function.Supplier; import static net.openhft.chronicle.bytes.NativeBytes.nativeBytes; public class FilePerKeyBasedKeyMarshallableValueStore<K, V extends Marshallable> implements KeyValueStore<K, V> { @NotNull private static final ThreadLocal<Wire> threadLocalValueWire = ThreadLocal.withInitial(() -> new TextWire(nativeBytes())); private final FilePerKeyValueStore kvStore; private final Function<K, String> keyToString; private final Function<String, K> stringToKey; private final Supplier<V> createValue; public FilePerKeyBasedKeyMarshallableValueStore( FilePerKeyValueStore kvStore, Function<K, String> keyToString, Function<String, K> stringToKey, Supplier<V> createValue) { this.kvStore = kvStore; this.keyToString = keyToString; this.stringToKey = stringToKey; this.createValue = createValue; } private static Wire valueWire() { Wire valueWire = threadLocalValueWire.get(); valueWire.clear(); return valueWire; } @Nullable private V bytesToValue(@Nullable BytesStore oldValue) { @Nullable V ret; if (oldValue != null) { V using = createValue.get(); using.readMarshallable(new TextWire(oldValue.bytesForRead())); ret = using; } else { ret = null; } return ret; } @Override public boolean put(K key, @NotNull V value) { Wire valueWire = valueWire(); value.writeMarshallable(valueWire); return kvStore.put(keyToString.apply(key), valueWire.bytes()); } @Nullable @Override public V getAndPut(K key, @NotNull V value) { Wire valueWire = valueWire(); value.writeMarshallable(valueWire); @Nullable BytesStore oldValue = kvStore.getAndPut(keyToString.apply(key), valueWire.bytes()); return bytesToValue(oldValue); } @Override public boolean remove(K key) { return kvStore.remove(keyToString.apply(key)); } @Nullable @Override public V getAndRemove(K key) { @Nullable BytesStore oldValue = kvStore.getAndRemove(keyToString.apply(key)); return bytesToValue(oldValue); } @Nullable @Override public V getUsing(K key, @Nullable Object value) { Wire valueWire = valueWire(); kvStore.getUsing(keyToString.apply(key), valueWire.bytes()); if (value == null) value = createValue.get(); ((ReadMarshallable) value).readMarshallable(valueWire); return (V) value; } @Override public long longSize() { return kvStore.longSize(); } @Override public void keysFor(int segment, @NotNull SubscriptionConsumer<K> kConsumer) throws InvalidSubscriberException { kvStore.keysFor(segment, key -> kConsumer.accept(stringToKey.apply(key))); } @Override public void entriesFor(int segment, @NotNull SubscriptionConsumer<MapEvent<K, V>> kvConsumer) throws InvalidSubscriberException { @NotNull String assetName = asset().fullName(); kvStore.entriesFor(segment, event -> kvConsumer.accept(InsertedEvent.of(assetName, stringToKey.apply(event.getKey()), bytesToValue(event.getValue()), false))); } @Override public void clear() { kvStore.clear(); } @Override public boolean containsValue(V value) { throw new UnsupportedOperationException(); } @NotNull @Override public Asset asset() { return kvStore.asset(); } @Nullable @Override public KeyValueStore<K, V> underlying() { return null; } @Override public void close() { kvStore.close(); } @Override public void accept(EngineReplication.ReplicationEntry replicationEntry) { throw new UnsupportedOperationException(); } }