// 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 static org.easymock.EasyMock.eq; import static org.easymock.EasyMock.expect; import java.time.Duration; import java.time.Instant; import java.util.concurrent.ExecutorService; import org.janusgraph.diskstorage.util.time.TimestampProviders; import org.easymock.EasyMock; import org.easymock.IMocksControl; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.janusgraph.diskstorage.keycolumnvalue.KeyColumnValueStore; import org.janusgraph.diskstorage.keycolumnvalue.StoreTransaction; import org.janusgraph.diskstorage.locking.consistentkey.ConsistentKeyLockerSerializer; import org.janusgraph.diskstorage.locking.consistentkey.LockCleanerService; import org.janusgraph.diskstorage.locking.consistentkey.StandardLockCleanerRunnable; import org.janusgraph.diskstorage.locking.consistentkey.StandardLockCleanerService; import org.janusgraph.diskstorage.util.KeyColumn; import org.janusgraph.diskstorage.util.StaticArrayBuffer; public class LockCleanerServiceTest { private IMocksControl ctrl; private IMocksControl relaxedCtrl;; private KeyColumnValueStore store; private StoreTransaction tx; private ExecutorService exec; private LockCleanerService svc; private final ConsistentKeyLockerSerializer codec = new ConsistentKeyLockerSerializer(); private final KeyColumn kc = new KeyColumn( new StaticArrayBuffer(new byte[]{(byte) 1}), new StaticArrayBuffer(new byte[]{(byte) 2})); @Before public void setupMocks() { relaxedCtrl = EasyMock.createControl(); tx = relaxedCtrl.createMock(StoreTransaction.class); ctrl = EasyMock.createStrictControl(); store = ctrl.createMock(KeyColumnValueStore.class); exec = ctrl.createMock(ExecutorService.class); } @After public void verifyMocks() { ctrl.verify(); } @Test public void testCleanCooldownBlocksRapidRequests() { final Instant cutoff = Instant.ofEpochMilli(1L); svc = new StandardLockCleanerService(store, codec, exec, Duration.ofSeconds(60L), TimestampProviders.MILLI); expect(exec.submit(eq(new StandardLockCleanerRunnable(store, kc, tx, codec, cutoff, TimestampProviders.MILLI)))).andReturn(null); ctrl.replay(); for (int i = 0; i < 500; i++) { svc.clean(kc, cutoff, tx); } } @Test public void testCleanCooldownElapses() throws InterruptedException { final Instant cutoff = Instant.ofEpochMilli(1L); Duration wait = Duration.ofMillis(500L); svc = new StandardLockCleanerService(store, codec, exec, wait, TimestampProviders.MILLI); expect(exec.submit(eq(new StandardLockCleanerRunnable(store, kc, tx, codec, cutoff, TimestampProviders.MILLI)))).andReturn(null); expect(exec.submit(eq(new StandardLockCleanerRunnable(store, kc, tx, codec, cutoff.plusMillis(1), TimestampProviders.MILLI)))).andReturn(null); ctrl.replay(); for (int i = 0; i < 2; i++) { svc.clean(kc, cutoff, tx); } TimestampProviders.MILLI.sleepFor(wait.plusMillis(1)); for (int i = 0; i < 2; i++) { svc.clean(kc, cutoff.plusMillis(1), tx); } } }