com.ibm.etcd.client.lock.EtcdLockClient Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of etcd-java Show documentation
Show all versions of etcd-java Show documentation
etcd3 java client and utilities
/*
* Copyright 2017, 2018 IBM Corp. All Rights Reserved.
*
* 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 com.ibm.etcd.client.lock;
import static java.util.concurrent.TimeUnit.NANOSECONDS;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeoutException;
import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.protobuf.ByteString;
import com.ibm.etcd.api.LockGrpc;
import com.ibm.etcd.api.LockRequest;
import com.ibm.etcd.api.LockResponse;
import com.ibm.etcd.api.UnlockRequest;
import com.ibm.etcd.api.UnlockResponse;
import com.ibm.etcd.client.EtcdClient;
import com.ibm.etcd.client.FluentRequest.AbstractFluentRequest;
import com.ibm.etcd.client.GrpcClient;
import com.ibm.etcd.client.lease.PersistentLease;
import io.grpc.MethodDescriptor;
import io.grpc.Status;
public final class EtcdLockClient implements LockClient {
// avoid volatile read on every invocation
private static final MethodDescriptor METHOD_LOCK =
LockGrpc.getLockMethod();
private static final MethodDescriptor METHOD_UNLOCK =
LockGrpc.getUnlockMethod();
protected final EtcdClient etcdClient;
protected final GrpcClient grpcClient;
public EtcdLockClient(GrpcClient grpcClient, EtcdClient etcdClient) {
this.grpcClient = grpcClient;
this.etcdClient = etcdClient;
}
final class EtcdLockRequest extends AbstractFluentRequest implements FluentLockRequest {
PersistentLease lease;
EtcdLockRequest(ByteString name) {
super(grpcClient, LockRequest.newBuilder().setName(name));
}
@Override
protected MethodDescriptor getMethod() {
return METHOD_LOCK;
}
@Override
protected boolean idempotent() {
return true;
}
@Override
public FluentLockRequest withLease(long leaseId) {
builder.setLease(leaseId);
lease = null;
return this;
}
@Override
public FluentLockRequest withLease(PersistentLease lease) {
this.lease = lease;
return this;
}
@Override
public final ListenableFuture async(Executor executor) {
if (lease == null) {
if (builder.getLease() != 0L) {
return super.async(executor);
} else {
lease = etcdClient.getSessionLease();
}
}
long plId = lease.getLeaseId();
if (plId != 0L) {
builder.setLease(plId);
return super.async(executor);
}
ListenableFuture fut;
if (deadline == null) {
fut = lease;
} else {
long remainingNanos = deadline.timeRemaining(NANOSECONDS);
fut = Futures.catching(Futures.withTimeout(lease,
remainingNanos, NANOSECONDS, grpcClient.getInternalExecutor()),
TimeoutException.class, te -> {
throw Status.DEADLINE_EXCEEDED.withCause(te)
.withDescription(String.format("deadline exceeded after %dns",
remainingNanos)).asRuntimeException();
}, MoreExecutors.directExecutor());
}
return Futures.transformAsync(fut, id -> {
builder.setLease(id);
return super.async(executor);
}, executor);
}
}
@Override
public FluentLockRequest lock(ByteString name) {
return new EtcdLockRequest(name);
}
final class EtcdUnlockRequest extends AbstractFluentRequest implements FluentUnlockRequest {
EtcdUnlockRequest(ByteString key) {
super(grpcClient, UnlockRequest.newBuilder().setKey(key));
}
@Override
protected MethodDescriptor getMethod() {
return METHOD_UNLOCK;
}
@Override
protected boolean idempotent() {
return true;
}
}
@Override
public FluentUnlockRequest unlock(ByteString key) {
return new EtcdUnlockRequest(key);
}
}