1 package com.atlassian.vcache.internal.core.service;
2
3 import com.atlassian.vcache.VCacheException;
4 import org.slf4j.Logger;
5 import org.slf4j.LoggerFactory;
6
7 import java.time.Duration;
8 import java.util.concurrent.TimeUnit;
9 import java.util.concurrent.locks.ReentrantLock;
10 import java.util.function.Supplier;
11
12 import static java.util.Objects.requireNonNull;
13
14
15
16
17
18 public class VCacheLock {
19 private static final Logger log = LoggerFactory.getLogger(VCacheLock.class);
20
21 private final ReentrantLock lock = new ReentrantLock();
22 private final String cacheName;
23 private final long lockTimeoutMillis;
24
25 public VCacheLock(String cacheName, Duration lockTimeout) {
26 this.cacheName = requireNonNull(cacheName);
27 this.lockTimeoutMillis = lockTimeout.toMillis();
28 }
29
30 public <R> R withLock(Supplier<R> supplier) {
31 lockWithTimeout();
32 try {
33 return supplier.get();
34 } finally {
35 lock.unlock();
36 }
37 }
38
39 public void withLock(Runnable runner) {
40 lockWithTimeout();
41 try {
42 runner.run();
43 } finally {
44 lock.unlock();
45 }
46 }
47
48 private void lockWithTimeout() {
49 try {
50 if (!lock.tryLock(lockTimeoutMillis, TimeUnit.MILLISECONDS)) {
51 log.warn("Timed out waiting for lock on cache: {}", cacheName);
52 throw new VCacheException("Timed out waiting for lock on cache: " + cacheName);
53 }
54 } catch (InterruptedException e) {
55 Thread.interrupted();
56 log.warn("Interrupted whilst waiting for a lock on cache: ", cacheName, e);
57 throw new VCacheException("Interrupted waiting for lock on cache: " + cacheName, e);
58 }
59 }
60 }