blob: d96f532a889b1c5004b58db1c90ceb514c78783f [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.reviewdb.client.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<Project.NameKey, ConcurrentMap<String, AtomicReference<Lock>>> refLockStore;
public FakeGlobalRefDatabase() {
keyValueStore = new MapMaker().concurrencyLevel(1).makeMap();
refLockStore = 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
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)
throws GlobalRefDbSystemError {
return Optional.ofNullable((T) projectRefDb(project).get(refName))
.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();
}
}
}