blob: 44c4fbb2fb64186072dfa0515b71868e1a8abc24 [file] [log] [blame]
// Copyright (C) 2019 GerritForge Ltd
//
// 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 com.gerritforge.gerrit.globalrefdb;
import com.google.common.collect.MapMaker;
import com.google.gerrit.entities.Project;
import java.util.Optional;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.junit.Ignore;
@Ignore
public class FakeGlobalRefDatabase implements GlobalRefDatabase {
private ConcurrentMap<Project.NameKey, ConcurrentMap<String, AtomicReference<ObjectId>>>
keyValueStore;
private ConcurrentMap<String, AtomicReference<?>> genericKeyValueStore;
private ConcurrentMap<Project.NameKey, ConcurrentMap<String, AtomicReference<Lock>>> refLockStore;
public FakeGlobalRefDatabase() {
keyValueStore = new MapMaker().concurrencyLevel(1).makeMap();
refLockStore = new MapMaker().concurrencyLevel(1).makeMap();
genericKeyValueStore = new MapMaker().concurrencyLevel(1).makeMap();
}
@Override
public boolean isUpToDate(Project.NameKey project, Ref ref) throws GlobalRefDbLockException {
AtomicReference<ObjectId> value = projectRefDb(project).get(ref.getName());
if (value == null) {
return true;
}
return ref.getObjectId().equals(value.get());
}
@Override
public boolean compareAndPut(Project.NameKey project, Ref currRef, ObjectId newRefValue)
throws GlobalRefDbSystemError {
ConcurrentMap<String, AtomicReference<ObjectId>> projectRefDb = projectRefDb(project);
AtomicReference<ObjectId> currValue = projectRefDb.get(currRef.getName());
if (currValue == null) {
projectRefDb.put(currRef.getName(), new AtomicReference<>(newRefValue));
return true;
}
return currValue.compareAndSet(currRef.getObjectId(), newRefValue);
}
@Override
@SuppressWarnings("unchecked")
public <T> boolean compareAndPut(Project.NameKey project, String refName, T currValue, T newValue)
throws GlobalRefDbSystemError {
String key = String.format("%s/%s", project.get(), refName);
AtomicReference<T> storedValue = (AtomicReference<T>) genericKeyValueStore.get(key);
if (storedValue == null) {
genericKeyValueStore.put(key, new AtomicReference<>(newValue));
return true;
}
return storedValue.compareAndSet(currValue, newValue);
}
@Override
public AutoCloseable lockRef(Project.NameKey project, String refName)
throws GlobalRefDbLockException {
ConcurrentMap<String, AtomicReference<Lock>> projectRefLock = projectRefLock(project);
AtomicReference<Lock> currLock = projectRefLock.get(refName);
if (currLock == null) {
Lock lock = new ReentrantLock();
lock.lock();
projectRefLock.put(refName, new AtomicReference<>(lock));
return new RefLock(lock);
}
Lock lock = currLock.get();
lock.lock();
return new RefLock(lock);
}
@Override
public boolean exists(Project.NameKey project, String refName) {
return projectRefDb(project).containsKey(refName);
}
@Override
public void remove(Project.NameKey project) throws GlobalRefDbSystemError {
keyValueStore.remove(project);
}
@Override
@SuppressWarnings("unchecked")
public <T> Optional<T> get(Project.NameKey project, String refName, Class<T> clazz)
throws GlobalRefDbSystemError {
String key = String.format("%s/%s", project.get(), refName);
return Optional.ofNullable((T) genericKeyValueStore.get(key))
.map(v -> ((AtomicReference<T>) v).get());
}
private ConcurrentMap<String, AtomicReference<ObjectId>> projectRefDb(Project.NameKey project) {
ConcurrentMap<String, AtomicReference<ObjectId>> projectRefDb = keyValueStore.get(project);
if (projectRefDb == null) {
projectRefDb = new MapMaker().concurrencyLevel(1).makeMap();
keyValueStore.put(project, projectRefDb);
}
return projectRefDb;
}
private ConcurrentMap<String, AtomicReference<Lock>> projectRefLock(Project.NameKey project) {
ConcurrentMap<String, AtomicReference<Lock>> projectRefLock = refLockStore.get(project);
if (projectRefLock == null) {
projectRefLock = new MapMaker().concurrencyLevel(1).makeMap();
refLockStore.put(project, projectRefLock);
}
return projectRefLock;
}
private static class RefLock implements AutoCloseable {
private Lock lock;
public RefLock(Lock lock) {
this.lock = lock;
}
@Override
public void close() throws Exception {
lock.unlock();
}
}
}