use of org.janusgraph.diskstorage.locking.consistentkey.ConsistentKeyLockStatus in project janusgraph by JanusGraph.
the class ConsistentKeyLockerTest method testCheckLocksDiesOnPermanentStorageException.
/**
* A single PermanentStorageException on getSlice() for a single lock is
* sufficient to make the method return immediately (regardless of whether
* other locks are waiting to be checked).
*
* @throws InterruptedException shouldn't happen
* @throws org.janusgraph.diskstorage.BackendException shouldn't happen
*/
@Test
public void testCheckLocksDiesOnPermanentStorageException() throws InterruptedException, BackendException {
// Setup a LockStatus for defaultLockID
ConsistentKeyLockStatus lockStatus = makeStatusNow();
currentTimeNS = currentTimeNS.plusNanos(1);
expect(lockState.getLocksForTx(defaultTx)).andReturn(ImmutableMap.of(defaultLockID, lockStatus));
expectSleepAfterWritingLock(lockStatus);
// First and only getSlice call throws a PSE
recordExceptionalLockGetSlice(new PermanentBackendException("Connection to storage cluster failed: peer is an IPv6 toaster"));
ctrl.replay();
PermanentBackendException pse = null;
try {
locker.checkLocks(defaultTx);
} catch (PermanentBackendException e) {
pse = e;
}
assertNotNull(pse);
}
use of org.janusgraph.diskstorage.locking.consistentkey.ConsistentKeyLockStatus in project janusgraph by JanusGraph.
the class ConsistentKeyLockerTest method testDeleteLocksSkipsToNextLockAfterMaxTemporaryStorageExceptions.
/**
* If lock deletion exceeds the temporary exception retry count when trying
* to delete a lock, it should move onto the next lock rather than returning
* and potentially leaving the remaining locks alone (not deleted).
*
* @throws org.janusgraph.diskstorage.BackendException shouldn't happen
*/
@Test
public void testDeleteLocksSkipsToNextLockAfterMaxTemporaryStorageExceptions() throws BackendException {
ConsistentKeyLockStatus defaultLS = makeStatusNow();
currentTimeNS = currentTimeNS.plusNanos(1);
expect(lockState.getLocksForTx(defaultTx)).andReturn(Maps.newLinkedHashMap(ImmutableMap.of(defaultLockID, defaultLS)));
expectDeleteLock(defaultLockID, defaultLockKey, defaultLS, new TemporaryBackendException("Storage cluster is busy"), new TemporaryBackendException("Storage cluster is busier"), new TemporaryBackendException("Storage cluster has reached peak business"));
ctrl.replay();
locker.deleteLocks(defaultTx);
}
use of org.janusgraph.diskstorage.locking.consistentkey.ConsistentKeyLockStatus in project janusgraph by JanusGraph.
the class ConsistentKeyLockerTest method testCheckLocksSucceedsWithSeniorAndJuniorClaimsBySelf.
/**
* If the checker retrieves a timestamp-ordered list of columns, where the
* list starts with an unbroken series of columns with the checker's rid but
* differing timestamps, then consider the lock successfully checked if the
* checker's expected timestamp occurs anywhere in that series of columns.
* <p/>
* This relaxation of the normal checking rules only triggers when either
* writeLock(...) issued mutate calls that appeared to fail client-side but
* which actually succeeded (e.g. hinted handoff or timeout)
*
* @throws InterruptedException shouldn't happen
* @throws org.janusgraph.diskstorage.BackendException shouldn't happen
*/
@Test
public void testCheckLocksSucceedsWithSeniorAndJuniorClaimsBySelf() throws InterruptedException, BackendException {
// Setup three lock columns differing only in timestamp
StaticBuffer myFirstLockCol = codec.toLockCol(currentTimeNS, defaultLockRid, times);
currentTimeNS = currentTimeNS.plusNanos(1);
StaticBuffer mySecondLockCol = codec.toLockCol(currentTimeNS, defaultLockRid, times);
ConsistentKeyLockStatus mySecondLS = makeStatusNow();
currentTimeNS = currentTimeNS.plusNanos(1);
StaticBuffer myThirdLockCol = codec.toLockCol(currentTimeNS, defaultLockRid, times);
currentTimeNS = currentTimeNS.plusNanos(1);
expect(lockState.getLocksForTx(defaultTx)).andReturn(ImmutableMap.of(defaultLockID, mySecondLS));
// Return defaultTx's second lock in a map when requested
currentTimeNS = currentTimeNS.plusSeconds(10);
expectSleepAfterWritingLock(mySecondLS);
// When the checker slices the store, return the senior lock col by a
// foreign tx and the junior lock col by defaultTx (in that order)
recordLockGetSlice(StaticArrayEntryList.of(StaticArrayEntry.of(myFirstLockCol, defaultLockVal), StaticArrayEntry.of(mySecondLockCol, defaultLockVal), StaticArrayEntry.of(myThirdLockCol, defaultLockVal)));
ctrl.replay();
locker.checkLocks(defaultTx);
}
use of org.janusgraph.diskstorage.locking.consistentkey.ConsistentKeyLockStatus in project janusgraph by JanusGraph.
the class ConsistentKeyLockerTest method testCheckLocksIdempotence.
/**
* Each written lock should be checked at most once. Test this by faking a
* single previously written lock using mocks and stubs and then calling
* checkLocks() twice. The second call should have no effect.
*
* @throws InterruptedException shouldn't happen
* @throws org.janusgraph.diskstorage.BackendException shouldn't happen
*/
@Test
public void testCheckLocksIdempotence() throws InterruptedException, BackendException {
// Fake a pre-existing valid lock
final ConsistentKeyLockStatus ls = makeStatusNow();
expect(lockState.getLocksForTx(defaultTx)).andReturn(ImmutableMap.of(defaultLockID, ls));
currentTimeNS = currentTimeNS.plusSeconds(10);
expectSleepAfterWritingLock(ls);
final StaticBuffer lc = codec.toLockCol(ls.getWriteTimestamp(), defaultLockRid, times);
recordLockGetSliceAndReturnSingleEntry(StaticArrayEntry.of(lc, defaultLockVal));
ctrl.replay();
locker.checkLocks(defaultTx);
ctrl.verify();
ctrl.reset();
// Return the faked lock in a map of size 1
expect(lockState.getLocksForTx(defaultTx)).andReturn(ImmutableMap.of(defaultLockID, ls));
ctrl.replay();
// At this point, checkLocks() should see that the single lock in the
// map returned above has already been checked and return immediately
locker.checkLocks(defaultTx);
}
use of org.janusgraph.diskstorage.locking.consistentkey.ConsistentKeyLockStatus in project janusgraph by JanusGraph.
the class ConsistentKeyLockerTest method testCheckLocksRetriesAfterSingleTemporaryStorageException.
/**
* The checker should retry getSlice() in the face of a
* TemporaryStorageException so long as the number of exceptional
* getSlice()s is fewer than the lock retry count. The retry count applies
* on a per-lock basis.
*
* @throws org.janusgraph.diskstorage.BackendException shouldn't happen
* @throws InterruptedException shouldn't happen
*/
@Test
public void testCheckLocksRetriesAfterSingleTemporaryStorageException() throws BackendException, InterruptedException {
// Setup one lock column
StaticBuffer lockCol = codec.toLockCol(currentTimeNS, defaultLockRid, times);
ConsistentKeyLockStatus lockStatus = makeStatusNow();
currentTimeNS = currentTimeNS.plusNanos(1);
expect(lockState.getLocksForTx(defaultTx)).andReturn(ImmutableMap.of(defaultLockID, lockStatus));
expectSleepAfterWritingLock(lockStatus);
// First getSlice will fail
TemporaryBackendException tse = new TemporaryBackendException("Storage cluster will be right back");
recordExceptionalLockGetSlice(tse);
// Second getSlice will succeed
recordLockGetSliceAndReturnSingleEntry(StaticArrayEntry.of(lockCol, defaultLockVal));
ctrl.replay();
locker.checkLocks(defaultTx);
// TODO run again with two locks instead of one and show that the retry count applies on a per-lock basis
}
Aggregations