use of org.janusgraph.diskstorage.StaticBuffer 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.StaticBuffer 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.StaticBuffer 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
}
use of org.janusgraph.diskstorage.StaticBuffer in project janusgraph by JanusGraph.
the class ConsistentKeyLockerTest method recordSuccessfulLockWrite.
private LockInfo recordSuccessfulLockWrite(StoreTransaction tx, long duration, TemporalUnit tu, StaticBuffer del) throws BackendException {
currentTimeNS = currentTimeNS.plusNanos(1);
expect(times.getTime()).andReturn(currentTimeNS);
final Instant lockNS = currentTimeNS;
StaticBuffer lockCol = codec.toLockCol(lockNS, defaultLockRid, times);
Entry add = StaticArrayEntry.of(lockCol, defaultLockVal);
StaticBuffer k = eq(defaultLockKey);
final List<Entry> adds = eq(Collections.singletonList(add));
final List<StaticBuffer> deletions;
if (null != del) {
deletions = eq(Collections.singletonList(del));
} else {
deletions = eq(ImmutableList.of());
}
store.mutate(k, adds, deletions, eq(tx));
expectLastCall().once();
currentTimeNS = currentTimeNS.plus(duration, tu);
expect(times.getTime()).andReturn(currentTimeNS);
ConsistentKeyLockStatus status = new ConsistentKeyLockStatus(lockNS, lockNS.plus(defaultExpireNS));
return new LockInfo(lockNS, status, lockCol);
}
use of org.janusgraph.diskstorage.StaticBuffer in project janusgraph by JanusGraph.
the class ConsistentKeyLockerTest method testWriteLockRetriesAfterOneStoreTimeout.
/**
* Test locker when first attempt to write to the store takes too long (but
* succeeds). Expected behavior is to call mutate on the store, adding a
* column with a new timestamp and deleting the column with the old
* (too-slow-to-write) timestamp.
*
* @throws org.janusgraph.diskstorage.BackendException shouldn't happen
*/
@Test
public void testWriteLockRetriesAfterOneStoreTimeout() throws BackendException {
expect(lockState.has(defaultTx, defaultLockID)).andReturn(false);
recordSuccessfulLocalLock();
// too slow
StaticBuffer firstCol = recordSuccessfulLockWrite(5, ChronoUnit.SECONDS, null).col;
// plenty fast
LockInfo secondLI = recordSuccessfulLockWrite(1, ChronoUnit.NANOS, firstCol);
recordSuccessfulLocalLock(secondLI.tsNS);
lockState.take(eq(defaultTx), eq(defaultLockID), eq(secondLI.stat));
ctrl.replay();
// SUT
locker.writeLock(defaultLockID, defaultTx);
}
Aggregations