use of com.couchbase.client.core.io.CollectionIdentifier in project couchbase-jvm-clients by couchbase.
the class KeyValueIntegrationTest method shortCircuitCollectionsIfNotAvailable.
@Test
@IgnoreWhen(hasCapabilities = { Capabilities.COLLECTIONS })
void shortCircuitCollectionsIfNotAvailable() {
String id = UUID.randomUUID().toString();
byte[] content = "hello, world".getBytes(UTF_8);
InsertRequest insertRequest = new InsertRequest(id, content, 0, 0, kvTimeout, core.context(), new CollectionIdentifier(config().bucketname(), Optional.of(CollectionIdentifier.DEFAULT_SCOPE), Optional.of("my_collection_name")), env.retryStrategy(), Optional.empty(), null);
core.send(insertRequest);
ExecutionException exception = assertThrows(ExecutionException.class, () -> insertRequest.response().get());
assertTrue(exception.getCause() instanceof FeatureNotAvailableException);
InsertRequest insertRequest2 = new InsertRequest(id, content, 0, 0, kvTimeout, core.context(), new CollectionIdentifier(config().bucketname(), Optional.of("my_custom_scope"), Optional.of(CollectionIdentifier.DEFAULT_COLLECTION)), env.retryStrategy(), Optional.empty(), null);
core.send(insertRequest2);
exception = assertThrows(ExecutionException.class, () -> insertRequest2.response().get());
assertTrue(exception.getCause() instanceof FeatureNotAvailableException);
}
use of com.couchbase.client.core.io.CollectionIdentifier in project couchbase-jvm-clients by couchbase.
the class AsyncCollection method mutateInRequest.
/**
* Helper method to create the underlying subdoc mutate request.
*
* @param id the outer document ID.
* @param specs the spec which specifies the type of mutations to perform.
* @param opts custom options to modify the mutation options.
* @return the subdoc mutate request.
*/
CompletableFuture<SubdocMutateRequest> mutateInRequest(final String id, final List<MutateInSpec> specs, final MutateInOptions.Built opts, final Duration timeout) {
notNullOrEmpty(id, "Id", () -> ReducedKeyValueErrorContext.create(id, collectionIdentifier));
notNullOrEmpty(specs, "MutateInSpecs", () -> ReducedKeyValueErrorContext.create(id, collectionIdentifier));
if (specs.isEmpty()) {
throw SubdocMutateRequest.errIfNoCommands(ReducedKeyValueErrorContext.create(id, collectionIdentifier));
} else if (specs.size() > SubdocMutateRequest.SUBDOC_MAX_FIELDS) {
throw SubdocMutateRequest.errIfTooManyCommands(ReducedKeyValueErrorContext.create(id, collectionIdentifier));
}
final boolean requiresBucketConfig = opts.createAsDeleted() || opts.storeSemantics() == StoreSemantics.REVIVE;
CompletableFuture<BucketConfig> bucketConfigFuture;
if (requiresBucketConfig) {
bucketConfigFuture = BucketConfigUtil.waitForBucketConfig(core, bucketName(), timeout).toFuture();
} else {
// Nothing will be using the bucket config so just provide null
bucketConfigFuture = CompletableFuture.completedFuture(null);
}
return bucketConfigFuture.thenCompose(bucketConfig -> {
RetryStrategy retryStrategy = opts.retryStrategy().orElse(environment.retryStrategy());
JsonSerializer serializer = opts.serializer() == null ? environment.jsonSerializer() : opts.serializer();
final RequestSpan span = environment.requestTracer().requestSpan(TracingIdentifiers.SPAN_REQUEST_KV_MUTATE_IN, opts.parentSpan().orElse(null));
ArrayList<SubdocMutateRequest.Command> commands = new ArrayList<>(specs.size());
final RequestSpan encodeSpan = environment.requestTracer().requestSpan(TracingIdentifiers.SPAN_REQUEST_ENCODING, span);
long start = System.nanoTime();
try {
for (int i = 0; i < specs.size(); i++) {
MutateInSpec spec = specs.get(i);
commands.add(spec.encode(serializer, i));
}
} finally {
encodeSpan.end();
}
long end = System.nanoTime();
// xattrs come first
commands.sort(Comparator.comparing(v -> !v.xattr()));
long expiry = opts.expiry().encode();
SubdocMutateRequest request = new SubdocMutateRequest(timeout, coreContext, collectionIdentifier, bucketConfig, retryStrategy, id, opts.storeSemantics() == StoreSemantics.INSERT, opts.storeSemantics() == StoreSemantics.UPSERT, opts.storeSemantics() == StoreSemantics.REVIVE, opts.accessDeleted(), opts.createAsDeleted(), commands, expiry, opts.preserveExpiry(), opts.cas(), opts.durabilityLevel(), span);
request.context().clientContext(opts.clientContext()).encodeLatency(end - start);
final CompletableFuture<SubdocMutateRequest> future = new CompletableFuture<>();
future.complete(request);
return future;
});
}
use of com.couchbase.client.core.io.CollectionIdentifier in project couchbase-jvm-clients by couchbase.
the class ReplicaHelper method getAnyReplicaAsync.
/**
* @param clientContext (nullable)
* @param parentSpan (nullable)
* @param responseMapper converts the GetReplicaResponse to the client's native result type
*/
public static <R> CompletableFuture<R> getAnyReplicaAsync(final Core core, final CollectionIdentifier collectionIdentifier, final String documentId, final Duration timeout, final RetryStrategy retryStrategy, final Map<String, Object> clientContext, final RequestSpan parentSpan, final Function<GetReplicaResponse, R> responseMapper) {
RequestSpan getAnySpan = core.context().environment().requestTracer().requestSpan(TracingIdentifiers.SPAN_GET_ANY_REPLICA, parentSpan);
CompletableFuture<List<CompletableFuture<R>>> listOfFutures = getAllReplicasAsync(core, collectionIdentifier, documentId, timeout, retryStrategy, clientContext, getAnySpan, responseMapper);
// Aggregating the futures here will discard the individual errors, which we don't need
CompletableFuture<R> anyReplicaFuture = new CompletableFuture<>();
listOfFutures.whenComplete((futures, throwable) -> {
if (throwable != null) {
anyReplicaFuture.completeExceptionally(throwable);
}
final AtomicBoolean successCompleted = new AtomicBoolean(false);
final AtomicInteger totalCompleted = new AtomicInteger(0);
final List<ErrorContext> nestedContexts = Collections.synchronizedList(new ArrayList<>());
futures.forEach(individual -> individual.whenComplete((result, error) -> {
int completed = totalCompleted.incrementAndGet();
if (error != null) {
if (error instanceof CompletionException && error.getCause() instanceof CouchbaseException) {
nestedContexts.add(((CouchbaseException) error.getCause()).context());
}
}
if (result != null && successCompleted.compareAndSet(false, true)) {
anyReplicaFuture.complete(result);
}
if (!successCompleted.get() && completed == futures.size()) {
anyReplicaFuture.completeExceptionally(new DocumentUnretrievableException(new AggregateErrorContext(nestedContexts)));
}
}));
});
return anyReplicaFuture.whenComplete((getReplicaResult, throwable) -> getAnySpan.end());
}
use of com.couchbase.client.core.io.CollectionIdentifier in project couchbase-jvm-clients by couchbase.
the class GetCollectionIdRequest method encode.
@Override
public ByteBuf encode(ByteBufAllocator alloc, int opaque, KeyValueChannelContext ctx) {
ByteBuf body = null;
try {
CollectionIdentifier ci = collectionIdentifier();
if (!ci.collection().isPresent()) {
throw InvalidArgumentException.fromMessage("A collection name needs to be present");
}
// Note that the scope can be empty, according to spec it is the same as _default scope
body = Unpooled.copiedBuffer(ci.scope().orElse("") + "." + ci.collection().get(), UTF_8);
return request(alloc, MemcacheProtocol.Opcode.COLLECTIONS_GET_CID, noDatatype(), noPartition(), opaque, noCas(), noExtras(), noKey(), body);
} finally {
ReferenceCountUtil.release(body);
}
}
use of com.couchbase.client.core.io.CollectionIdentifier in project couchbase-jvm-clients by couchbase.
the class CircuitBreakerIntegrationTest method shouldTriggerWithTimeouts.
@Test
void shouldTriggerWithTimeouts() {
int threshold = collection.environment().ioConfig().kvCircuitBreakerConfig().volumeThreshold();
int timeouts = 0;
int cancellations = 0;
for (int i = 0; i < threshold * 3; i++) {
FailingGetRequestOnEncode request = new FailingGetRequestOnEncode("foo", Duration.ofMillis(1), collection.core().context(), new CollectionIdentifier(config().bucketname(), Optional.of(collection.scopeName()), Optional.of(collection.name())), FailFastRetryStrategy.INSTANCE);
collection.core().send(request);
try {
request.response().get();
fail();
} catch (ExecutionException ex) {
if (ex.getCause() instanceof TimeoutException) {
timeouts++;
} else if (ex.getCause() instanceof RequestCanceledException) {
cancellations++;
CancellationReason reason = ((RequestCanceledException) ex.getCause()).context().requestContext().request().cancellationReason();
assertEquals(reason.innerReason(), RetryReason.ENDPOINT_CIRCUIT_OPEN);
}
} catch (Throwable t) {
fail(t);
}
}
assertTrue(timeouts > 0);
assertTrue(cancellations > 0);
}
Aggregations