use of com.palantir.lock.LockClient in project atlasdb by palantir.
the class InMemoryAtlasDbFactory method createInMemoryTransactionManagerInternal.
private static SerializableTransactionManager createInMemoryTransactionManagerInternal(Set<Schema> schemas) {
TimestampService ts = new InMemoryTimestampService();
KeyValueService keyValueService = new InMemoryKeyValueService(false);
schemas.forEach(s -> Schemas.createTablesAndIndexes(s, keyValueService));
TransactionTables.createTables(keyValueService);
TransactionService transactionService = TransactionServices.createTransactionService(keyValueService);
LockService lock = LockRefreshingLockService.create(LockServiceImpl.create(LockServerOptions.builder().isStandaloneServer(false).build()));
LockClient client = LockClient.of("in memory atlasdb instance");
ConflictDetectionManager conflictManager = ConflictDetectionManagers.createWithoutWarmingCache(keyValueService);
SweepStrategyManager sweepStrategyManager = SweepStrategyManagers.createDefault(keyValueService);
CleanupFollower follower = CleanupFollower.create(schemas);
Cleaner cleaner = new DefaultCleanerBuilder(keyValueService, lock, ts, client, ImmutableList.of(follower), transactionService).buildCleaner();
SerializableTransactionManager ret = SerializableTransactionManager.createForTest(keyValueService, ts, client, lock, transactionService, Suppliers.ofInstance(AtlasDbConstraintCheckingMode.FULL_CONSTRAINT_CHECKING_THROWS_EXCEPTIONS), conflictManager, sweepStrategyManager, cleaner, DEFAULT_MAX_CONCURRENT_RANGES, DEFAULT_GET_RANGES_CONCURRENCY, () -> DEFAULT_TIMESTAMP_CACHE_SIZE, MultiTableSweepQueueWriter.NO_OP);
cleaner.start(ret);
return ret;
}
use of com.palantir.lock.LockClient in project atlasdb by palantir.
the class SnapshotTransactionTest method testTransactionAtomicity.
@Test
public void testTransactionAtomicity() throws Exception {
// This test runs multiple transactions in parallel, with KeyValueService.put calls throwing
// a RuntimeException from time to time and hanging other times. which effectively kills the
// thread. We ensure that every transaction either adds 5 rows to the table or adds 0 rows
// by checking at the end that the number of rows is a multiple of 5.
final TableReference tableRef = TABLE;
Random random = new Random(1);
final UnstableKeyValueService unstableKvs = new UnstableKeyValueService(keyValueService, random);
final TestTransactionManager unstableTransactionManager = new TestTransactionManagerImpl(unstableKvs, timestampService, lockClient, lockService, transactionService, conflictDetectionManager, sweepStrategyManager, sweepQueue);
ScheduledExecutorService service = PTExecutors.newScheduledThreadPool(20);
for (int i = 0; i < 30; i++) {
final int threadNumber = i;
service.schedule((Callable<Void>) () -> {
if (threadNumber == 10) {
unstableKvs.setRandomlyThrow(true);
}
if (threadNumber == 20) {
unstableKvs.setRandomlyHang(true);
}
Transaction transaction = unstableTransactionManager.createNewTransaction();
BatchingVisitable<RowResult<byte[]>> results = transaction.getRange(tableRef, RangeRequest.builder().build());
final MutableInt nextIndex = new MutableInt(0);
results.batchAccept(1, AbortingVisitors.batching((AbortingVisitor<RowResult<byte[]>, Exception>) row -> {
byte[] dataBytes = row.getColumns().get(PtBytes.toBytes("data"));
BigInteger dataValue = new BigInteger(dataBytes);
nextIndex.setValue(Math.max(nextIndex.toInteger(), dataValue.intValue() + 1));
return true;
}));
// rows to the table.
for (int j = 0; j < 5; j++) {
int rowNumber = nextIndex.toInteger() + j;
Cell cell = Cell.create(PtBytes.toBytes("row" + rowNumber), PtBytes.toBytes("data"));
transaction.put(tableRef, ImmutableMap.of(cell, BigInteger.valueOf(rowNumber).toByteArray()));
Thread.yield();
}
transaction.commit();
return null;
}, i * 20, TimeUnit.MILLISECONDS);
}
service.shutdown();
service.awaitTermination(1, TimeUnit.SECONDS);
// Verify each table has a number of rows that's a multiple of 5
Transaction verifyTransaction = txManager.createNewTransaction();
BatchingVisitable<RowResult<byte[]>> results = verifyTransaction.getRange(tableRef, RangeRequest.builder().build());
final MutableInt numRows = new MutableInt(0);
results.batchAccept(1, AbortingVisitors.batching((AbortingVisitor<RowResult<byte[]>, Exception>) row -> {
numRows.increment();
return true;
}));
Assert.assertEquals(0, numRows.toInteger() % 5);
}
use of com.palantir.lock.LockClient in project atlasdb by palantir.
the class LockServiceImpl method lockWithFullLockResponse.
@Override
public // We're concerned about sanitizing logs at the info level and above. This method just logs at debug and info.
LockResponse lockWithFullLockResponse(LockClient client, LockRequest request) throws InterruptedException {
Preconditions.checkNotNull(client);
Preconditions.checkArgument(!client.equals(INTERNAL_LOCK_GRANT_CLIENT));
Preconditions.checkArgument(request.getLockTimeout().compareTo(maxAllowedLockTimeout) <= 0, "Requested lock timeout (%s) is greater than maximum allowed lock timeout (%s)", request.getLockTimeout(), maxAllowedLockTimeout);
long startTime = System.currentTimeMillis();
if (requestLogger.isDebugEnabled()) {
requestLogger.debug("LockServiceImpl processing lock request {} for requesting thread {}", UnsafeArg.of("lockRequest", request), SafeArg.of("requestingThread", request.getCreatingThreadName()));
}
Map<ClientAwareReadWriteLock, LockMode> locks = Maps.newLinkedHashMap();
if (isShutDown.get()) {
throw new ServiceNotAvailableException("This lock server is shut down.");
}
try {
boolean indefinitelyBlocking = isIndefinitelyBlocking(request.getBlockingMode());
if (indefinitelyBlocking) {
indefinitelyBlockingThreads.add(Thread.currentThread());
}
outstandingLockRequestMultimap.put(client, request);
Map<LockDescriptor, LockClient> failedLocks = Maps.newHashMap();
@Nullable Long deadline = (request.getBlockingDuration() == null) ? null : System.nanoTime() + request.getBlockingDuration().toNanos();
if (request.getBlockingMode() == BLOCK_UNTIL_TIMEOUT) {
if (request.getLockGroupBehavior() == LOCK_AS_MANY_AS_POSSIBLE) {
tryLocks(client, request, DO_NOT_BLOCK, null, LOCK_AS_MANY_AS_POSSIBLE, locks, failedLocks);
}
}
tryLocks(client, request, request.getBlockingMode(), deadline, request.getLockGroupBehavior(), locks, failedLocks);
if (request.getBlockingMode() == BlockingMode.BLOCK_INDEFINITELY_THEN_RELEASE) {
if (log.isTraceEnabled()) {
logNullResponse(client, request, null);
}
if (requestLogger.isDebugEnabled()) {
requestLogger.debug("Timed out requesting {} for requesting thread {} after {} ms", UnsafeArg.of("request", request), SafeArg.of("threadName", request.getCreatingThreadName()), SafeArg.of("timeoutMillis", System.currentTimeMillis() - startTime));
}
return new LockResponse(failedLocks);
}
if (locks.isEmpty() || ((request.getLockGroupBehavior() == LOCK_ALL_OR_NONE) && (locks.size() < request.getLockDescriptors().size()))) {
if (log.isTraceEnabled()) {
logNullResponse(client, request, null);
}
if (requestLogger.isDebugEnabled()) {
requestLogger.debug("Failed to acquire all locks for {} for requesting thread {} after {} ms", UnsafeArg.of("request", request), SafeArg.of("threadName", request.getCreatingThreadName()), SafeArg.of("waitMillis", System.currentTimeMillis() - startTime));
}
if (requestLogger.isTraceEnabled()) {
logLockAcquisitionFailure(failedLocks);
}
return new LockResponse(null, failedLocks);
}
Builder<LockDescriptor, LockMode> lockDescriptorMap = ImmutableSortedMap.naturalOrder();
for (Entry<ClientAwareReadWriteLock, LockMode> entry : locks.entrySet()) {
lockDescriptorMap.put(entry.getKey().getDescriptor(), entry.getValue());
}
if (request.getVersionId() != null) {
versionIdMap.put(client, request.getVersionId());
}
HeldLocksToken token = createHeldLocksToken(client, LockCollections.of(lockDescriptorMap.build()), LockCollections.of(locks), request.getLockTimeout(), request.getVersionId(), request.getCreatingThreadName());
locks.clear();
if (log.isTraceEnabled()) {
logNullResponse(client, request, token);
}
if (Thread.interrupted()) {
throw new InterruptedException("Interrupted while locking.");
}
if (requestLogger.isDebugEnabled()) {
requestLogger.debug("Successfully acquired locks {} for requesting thread {} after {} ms", UnsafeArg.of("request", request), SafeArg.of("threadName", request.getCreatingThreadName()), SafeArg.of("waitMillis", System.currentTimeMillis() - startTime));
}
return new LockResponse(token, failedLocks);
} finally {
outstandingLockRequestMultimap.remove(client, request);
indefinitelyBlockingThreads.remove(Thread.currentThread());
try {
for (Entry<ClientAwareReadWriteLock, LockMode> entry : locks.entrySet()) {
entry.getKey().get(client, entry.getValue()).unlock();
}
} catch (Throwable e) {
// (authorized)
log.error("Internal lock server error: state has been corrupted!!", UnsafeArg.of("exception", e), SafeArg.of("stacktrace", e.getStackTrace()));
throw Throwables.throwUncheckedException(e);
}
}
}
use of com.palantir.lock.LockClient in project atlasdb by palantir.
the class LockServiceImpl method unlockInternal.
private <T extends ExpiringToken> boolean unlockInternal(T token, ConcurrentMap<T, HeldLocks<T>> heldLocksMap) {
@Nullable HeldLocks<T> heldLocks = heldLocksMap.remove(token);
if (heldLocks == null) {
return false;
}
long heldDuration = System.currentTimeMillis() - token.getCreationDateMs();
if (requestLogger.isDebugEnabled()) {
requestLogger.debug("Releasing locks {} after holding for {} ms", UnsafeArg.of("heldLocks", heldLocks), SafeArg.of("heldDuration", heldDuration));
}
@Nullable LockClient client = heldLocks.realToken.getClient();
if (client == null) {
client = INTERNAL_LOCK_GRANT_CLIENT;
} else {
lockClientMultimap.remove(client, token);
}
for (Entry<? extends ClientAwareReadWriteLock, LockMode> entry : heldLocks.locks.entries()) {
entry.getKey().get(client, entry.getValue()).unlock();
}
if (heldLocks.realToken.getVersionId() != null) {
versionIdMap.remove(client, heldLocks.realToken.getVersionId());
}
return true;
}
use of com.palantir.lock.LockClient in project atlasdb by palantir.
the class LockServiceImpl method tryLocks.
private void tryLocks(LockClient client, LockRequest request, BlockingMode blockingMode, @Nullable Long deadline, LockGroupBehavior lockGroupBehavior, Map<? super ClientAwareReadWriteLock, ? super LockMode> locks, Map<? super LockDescriptor, ? super LockClient> failedLocks) throws InterruptedException {
String previousThreadName = null;
try {
previousThreadName = updateThreadName(request);
for (Entry<LockDescriptor, LockMode> entry : request.getLockDescriptors().entries()) {
if (blockingMode == BlockingMode.BLOCK_INDEFINITELY_THEN_RELEASE && !descriptorToLockMap.asMap().containsKey(entry.getKey())) {
continue;
}
ClientAwareReadWriteLock lock;
try {
lock = descriptorToLockMap.get(entry.getKey());
} catch (ExecutionException e) {
throw new RuntimeException(e.getCause());
}
if (locks.containsKey(lock)) {
// This is the 2nd time we are calling tryLocks and we already locked this one.
continue;
}
long startTime = System.currentTimeMillis();
@Nullable LockClient currentHolder = tryLock(lock.get(client, entry.getValue()), blockingMode, deadline);
if (log.isDebugEnabled() || isSlowLogEnabled()) {
long responseTimeMillis = System.currentTimeMillis() - startTime;
logSlowLockAcquisition(entry.getKey().toString(), currentHolder, responseTimeMillis);
}
if (currentHolder == null) {
locks.put(lock, entry.getValue());
} else {
failedLocks.put(entry.getKey(), currentHolder);
if (lockGroupBehavior == LOCK_ALL_OR_NONE) {
return;
}
}
}
} finally {
if (previousThreadName != null) {
tryRenameThread(previousThreadName);
}
}
}
Aggregations