use of com.thinkaurelius.titan.diskstorage.keycolumnvalue.KeySliceQuery in project titan by thinkaurelius.
the class ExpectedValueCheckingTest method testMutateManyWithLockUsesConsistentTx.
@Test
public void testMutateManyWithLockUsesConsistentTx() throws BackendException {
final ImmutableList<Entry> adds = ImmutableList.of(StaticArrayEntry.of(DATA_COL, DATA_VAL));
final ImmutableList<StaticBuffer> dels = ImmutableList.<StaticBuffer>of();
Map<String, Map<StaticBuffer, KCVMutation>> mutations = ImmutableMap.<String, Map<StaticBuffer, KCVMutation>>of(STORE_NAME, ImmutableMap.<StaticBuffer, KCVMutation>of(DATA_KEY, new KCVMutation(adds, dels)));
final KeyColumn kc = new KeyColumn(LOCK_KEY, LOCK_COL);
// Acquire a lock
backingLocker.writeLock(kc, consistentTx);
// 2. Run mutateMany
// 2.1. Check locks & expected values before mutating data
backingLocker.checkLocks(consistentTx);
StaticBuffer nextBuf = BufferUtil.nextBiggerBuffer(kc.getColumn());
KeySliceQuery expectedValueQuery = new KeySliceQuery(kc.getKey(), kc.getColumn(), nextBuf);
// expected value read must use strong consistency
expect(backingStore.getSlice(expectedValueQuery, consistentTx)).andReturn(StaticArrayEntryList.of(StaticArrayEntry.of(LOCK_COL, LOCK_VAL)));
// 2.2. Run mutateMany on backing manager to modify data
// writes by txs with locks must use strong consistency
backingManager.mutateMany(mutations, consistentTx);
ctrl.replay();
// Lock acquisition
expectStore.acquireLock(LOCK_KEY, LOCK_COL, LOCK_VAL, expectTx);
// Mutate
expectManager.mutateMany(mutations, expectTx);
}
use of com.thinkaurelius.titan.diskstorage.keycolumnvalue.KeySliceQuery in project titan by thinkaurelius.
the class ExpectedValueCheckingTest method testMutateWithLockUsesConsistentTx.
@Test
public void testMutateWithLockUsesConsistentTx() throws BackendException {
final ImmutableList<Entry> adds = ImmutableList.of(StaticArrayEntry.of(DATA_COL, DATA_VAL));
final ImmutableList<StaticBuffer> dels = ImmutableList.<StaticBuffer>of();
final KeyColumn kc = new KeyColumn(LOCK_KEY, LOCK_COL);
// 1. Acquire a lock
backingLocker.writeLock(kc, consistentTx);
// 2. Run a mutation
// N.B. mutation coordinates do not overlap with the lock, but consistentTx should be used anyway
// 2.1. Check locks & expected values before mutating data
backingLocker.checkLocks(consistentTx);
StaticBuffer nextBuf = BufferUtil.nextBiggerBuffer(kc.getColumn());
KeySliceQuery expectedValueQuery = new KeySliceQuery(kc.getKey(), kc.getColumn(), nextBuf);
// expected value read must use strong consistency
expect(backingStore.getSlice(expectedValueQuery, consistentTx)).andReturn(StaticArrayEntryList.of(StaticArrayEntry.of(LOCK_COL, LOCK_VAL)));
// 2.2. Mutate data
// writes by txs with locks must use strong consistency
backingStore.mutate(DATA_KEY, adds, dels, consistentTx);
ctrl.replay();
// 1. Lock acquisition
expectStore.acquireLock(LOCK_KEY, LOCK_COL, LOCK_VAL, expectTx);
// 2. Mutate
expectStore.mutate(DATA_KEY, adds, dels, expectTx);
}
use of com.thinkaurelius.titan.diskstorage.keycolumnvalue.KeySliceQuery in project titan by thinkaurelius.
the class ExpirationCacheTest method verifyResults.
private void verifyResults(StaticBuffer key, List<StaticBuffer> keys, SliceQuery query, int expectedResults) throws Exception {
CacheTransaction tx = getCacheTx();
assertEquals(expectedResults, cache.getSlice(new KeySliceQuery(key, query), tx).size());
Map<StaticBuffer, EntryList> results = cache.getSlice(keys, query, tx);
assertEquals(keys.size(), results.size());
assertEquals(expectedResults, results.get(key).size());
tx.commit();
}
use of com.thinkaurelius.titan.diskstorage.keycolumnvalue.KeySliceQuery in project titan by thinkaurelius.
the class MultiKeySliceQuery method execute.
public List<EntryList> execute(final BackendTransaction tx) {
int total = 0;
List<EntryList> result = new ArrayList<EntryList>(4);
for (KeySliceQuery ksq : queries) {
EntryList next = tx.indexQuery(ksq.updateLimit(getLimit() - total));
result.add(next);
total += next.size();
if (total >= getLimit())
break;
}
return result;
}
use of com.thinkaurelius.titan.diskstorage.keycolumnvalue.KeySliceQuery in project titan by thinkaurelius.
the class ConsistentKeyIDAuthority method getIDBlock.
@Override
public synchronized IDBlock getIDBlock(final int partition, final int idNamespace, Duration timeout) throws BackendException {
Preconditions.checkArgument(partition >= 0 && partition < (1 << partitionBitWdith), "Invalid partition id [%s] for bit width [%s]", partition, partitionBitWdith);
//can be any non-negative value
Preconditions.checkArgument(idNamespace >= 0);
final Timer methodTime = times.getTimer().start();
final long blockSize = getBlockSize(idNamespace);
final long idUpperBound = getIdUpperBound(idNamespace);
final int maxAvailableBits = (VariableLong.unsignedBitLength(idUpperBound) - 1) - uniqueIdBitWidth;
Preconditions.checkArgument(maxAvailableBits > 0, "Unique id bit width [%s] is too wide for id-namespace [%s] id bound [%s]", uniqueIdBitWidth, idNamespace, idUpperBound);
final long idBlockUpperBound = (1l << maxAvailableBits);
final List<Integer> exhaustedUniquePIDs = new ArrayList<Integer>(randomUniqueIDLimit);
Duration backoffMS = idApplicationWaitMS;
Preconditions.checkArgument(idBlockUpperBound > blockSize, "Block size [%s] is larger than upper bound [%s] for bit width [%s]", blockSize, idBlockUpperBound, uniqueIdBitWidth);
while (methodTime.elapsed().compareTo(timeout) < 0) {
final int uniquePID = getUniquePartitionID();
final StaticBuffer partitionKey = getPartitionKey(partition, idNamespace, uniquePID);
try {
long nextStart = getCurrentID(partitionKey);
if (idBlockUpperBound - blockSize <= nextStart) {
log.info("ID overflow detected on partition({})-namespace({}) with uniqueid {}. Current id {}, block size {}, and upper bound {} for bit width {}.", partition, idNamespace, uniquePID, nextStart, blockSize, idBlockUpperBound, uniqueIdBitWidth);
if (randomizeUniqueId) {
exhaustedUniquePIDs.add(uniquePID);
if (exhaustedUniquePIDs.size() == randomUniqueIDLimit)
throw new IDPoolExhaustedException(String.format("Exhausted %d uniqueid(s) on partition(%d)-namespace(%d): %s", exhaustedUniquePIDs.size(), partition, idNamespace, Joiner.on(",").join(exhaustedUniquePIDs)));
else
throw new UniqueIDExhaustedException(String.format("Exhausted ID partition(%d)-namespace(%d) with uniqueid %d (uniqueid attempt %d/%d)", partition, idNamespace, uniquePID, exhaustedUniquePIDs.size(), randomUniqueIDLimit));
}
throw new IDPoolExhaustedException("Exhausted id block for partition(" + partition + ")-namespace(" + idNamespace + ") with upper bound: " + idBlockUpperBound);
}
// calculate the start (inclusive) and end (exclusive) of the allocation we're about to attempt
assert idBlockUpperBound - blockSize > nextStart;
long nextEnd = nextStart + blockSize;
StaticBuffer target = null;
// attempt to write our claim on the next id block
boolean success = false;
try {
Timer writeTimer = times.getTimer().start();
target = getBlockApplication(nextEnd, writeTimer.getStartTime());
// copy for the inner class
final StaticBuffer finalTarget = target;
BackendOperation.execute(new BackendOperation.Transactional<Boolean>() {
@Override
public Boolean call(StoreTransaction txh) throws BackendException {
idStore.mutate(partitionKey, Arrays.asList(StaticArrayEntry.of(finalTarget)), KeyColumnValueStore.NO_DELETIONS, txh);
return true;
}
}, this, times);
writeTimer.stop();
Duration writeElapsed = writeTimer.elapsed();
if (idApplicationWaitMS.compareTo(writeElapsed) < 0) {
throw new TemporaryBackendException("Wrote claim for id block [" + nextStart + ", " + nextEnd + ") in " + (writeElapsed) + " => too slow, threshold is: " + idApplicationWaitMS);
} else {
assert 0 != target.length();
final StaticBuffer[] slice = getBlockSlice(nextEnd);
/* At this point we've written our claim on [nextStart, nextEnd),
* but we haven't yet guaranteed the absence of a contending claim on
* the same id block from another machine
*/
sleepAndConvertInterrupts(idApplicationWaitMS.plus(waitGracePeriod));
// Read all id allocation claims on this partition, for the counter value we're claiming
List<Entry> blocks = BackendOperation.execute(new BackendOperation.Transactional<List<Entry>>() {
@Override
public List<Entry> call(StoreTransaction txh) throws BackendException {
return idStore.getSlice(new KeySliceQuery(partitionKey, slice[0], slice[1]), txh);
}
}, this, times);
if (blocks == null)
throw new TemporaryBackendException("Could not read from storage");
if (blocks.isEmpty())
throw new PermanentBackendException("It seems there is a race-condition in the block application. " + "If you have multiple Titan instances running on one physical machine, ensure that they have unique machine idAuthorities");
/* If our claim is the lexicographically first one, then our claim
* is the most senior one and we own this id block
*/
if (target.equals(blocks.get(0).getColumnAs(StaticBuffer.STATIC_FACTORY))) {
ConsistentKeyIDBlock idblock = new ConsistentKeyIDBlock(nextStart, blockSize, uniqueIdBitWidth, uniquePID);
if (log.isDebugEnabled()) {
log.debug("Acquired ID block [{}] on partition({})-namespace({}) (my rid is {})", new Object[] { idblock, partition, idNamespace, new String(uid) });
}
success = true;
return idblock;
} else {
// Another claimant beat us to this id block -- try again.
log.debug("Failed to acquire ID block [{},{}) (another host claimed it first)", nextStart, nextEnd);
}
}
} finally {
if (!success && null != target) {
//Delete claim to not pollute id space
for (int attempt = 0; attempt < rollbackAttempts; attempt++) {
try {
// copy for the inner class
final StaticBuffer finalTarget = target;
BackendOperation.execute(new BackendOperation.Transactional<Boolean>() {
@Override
public Boolean call(StoreTransaction txh) throws BackendException {
idStore.mutate(partitionKey, KeyColumnValueStore.NO_ADDITIONS, Arrays.asList(finalTarget), txh);
return true;
}
}, new //Use normal consistency level for these non-critical delete operations
BackendOperation.TransactionalProvider() {
@Override
public StoreTransaction openTx() throws BackendException {
return manager.beginTransaction(storeTxConfigBuilder.build());
}
@Override
public void close() {
}
}, times);
break;
} catch (BackendException e) {
log.warn("Storage exception while deleting old block application - retrying in {}", rollbackWaitTime, e);
if (!rollbackWaitTime.isZero())
sleepAndConvertInterrupts(rollbackWaitTime);
}
}
}
}
} catch (UniqueIDExhaustedException e) {
// No need to increment the backoff wait time or to sleep
log.warn(e.getMessage());
} catch (TemporaryBackendException e) {
backoffMS = Durations.min(backoffMS.multipliedBy(2), idApplicationWaitMS.multipliedBy(32));
log.warn("Temporary storage exception while acquiring id block - retrying in {}: {}", backoffMS, e);
sleepAndConvertInterrupts(backoffMS);
}
}
throw new TemporaryLockingException(String.format("Reached timeout %d (%s elapsed) when attempting to allocate id block on partition(%d)-namespace(%d)", timeout, methodTime.toString(), partition, idNamespace));
}
Aggregations