// Copyright 2017 JanusGraph Authors
//
// 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 org.janusgraph.diskstorage.locking;
import com.google.common.collect.MapMaker;
import org.janusgraph.diskstorage.keycolumnvalue.StoreTransaction;
import org.janusgraph.diskstorage.util.KeyColumn;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
/**
* A store for {@code LockStatus} objects. Thread-safe so long as the method
* calls with any given {@code StoreTransaction} are serial. Put another way,
* thread-safety is only broken by concurrently calling this class's methods
* with the same {@code StoreTransaction} instance in the arguments to each
* concurrent call.
*
* @see AbstractLocker
* @param <S>
* The {@link LockStatus} type.
*/
public class LockerState<S> {
/**
* Locks taken in the LocalLockMediator and written to the store (but not
* necessarily checked)
*/
private final ConcurrentMap<StoreTransaction, Map<KeyColumn, S>> locks;
public LockerState() {
// TODO this wild guess at the concurrency level should not be hardcoded
this(new MapMaker().concurrencyLevel(8).weakKeys()
.<StoreTransaction, Map<KeyColumn, S>> makeMap());
}
public LockerState(ConcurrentMap<StoreTransaction, Map<KeyColumn, S>> locks) {
this.locks = locks;
}
public boolean has(StoreTransaction tx, KeyColumn kc) {
return getLocksForTx(tx).containsKey(kc);
}
public void take(StoreTransaction tx, KeyColumn kc, S ls) {
getLocksForTx(tx).put(kc, ls);
}
public void release(StoreTransaction tx, KeyColumn kc) {
getLocksForTx(tx).remove(kc);
}
public Map<KeyColumn, S> getLocksForTx(StoreTransaction tx) {
Map<KeyColumn, S> m = locks.get(tx);
if (null == m) {
m = new HashMap<KeyColumn, S>();
final Map<KeyColumn, S> x = locks.putIfAbsent(tx, m);
if (null != x) {
m = x;
}
}
return m;
}
}