All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.couchbase.transactions.AttemptContext Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2021 Couchbase, Inc.
 *
 * 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.couchbase.transactions;

import com.couchbase.client.core.annotation.Stability;
import com.couchbase.client.core.error.CouchbaseException;
import com.couchbase.client.java.Collection;
import com.couchbase.client.java.Scope;
import com.couchbase.client.java.json.JsonObject;
import com.couchbase.client.java.query.QueryResult;
import com.couchbase.transactions.log.TransactionLogger;
import com.couchbase.transactions.util.SchedulerUtil;

import java.util.Objects;
import java.util.Optional;

/**
 * Provides methods to allow an application's transaction logic to read, mutate, insert and delete documents, as well
 * as
 * commit or rollback the transaction.
 * 

* These methods are blocking/synchronous. See {@link AttemptContextReactive} for the asynchronous version (which is * the * preferred option, and which this class largely simply wraps). */ public class AttemptContext { private final AttemptContextReactive reactive; AttemptContext(AttemptContextReactive reactive) { Objects.requireNonNull(reactive); this.reactive = reactive; } AttemptContextReactive ctx() { return reactive; } /** * Gives access to the attempt's logger, allowing application trace to be interleaved with transaction trace. */ public TransactionLogger logger() { return ctx().LOGGER; } /** * Gets a document from the specified Couchbase bucket matching the specified id. It's * returned * as Optional.empty() if not found. * * @param collection the Couchbase collection the document exists on * @param id the document's ID * @return an Optional containing the document, or Optional.empty() if not found */ public Optional getOptional(Collection collection, String id) { Optional out = reactive.getOptional(collection.reactive(), id) .publishOn(SchedulerUtil.schedulerBlocking) .block(); // Semantics of .block() are to return null if the Mono completes with empty if (out != null) { return out; } else { return Optional.empty(); } } /** * Gets a document from the specified Couchbase bucket matching the specified id. If * the document * is not * found, a DocumentNotFoundException is thrown. If not caught inside the transaction logic, this * particular exception will cause the overall transaction to abort with a thrown TransactionFailed. * * @param collection the Couchbase collection the document exists on * @param id the document's ID * @return a TransactionGetResult containing the document */ public TransactionGetResult get(Collection collection, String id) { return reactive.get(collection.reactive(), id) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Mutates the specified doc with new content, using the * document's last {@link TransactionGetResult#cas()}. *

* The mutation is staged until the transaction is committed. That is, any read of the document by any Couchbase * component will see the document's current value, rather than this staged or 'dirty' data. If the attempt is * rolled back, the staged mutation will be removed. *

* This staged data effectively locks the document from other transactional writes until the attempt completes * (commits or rolls back). *

* If the mutation fails with a CasMismatchException, or any other exception, the transaction will * automatically * rollback this attempt, then retry. * * @param doc the doc to be updated * @param content the content to replace the doc with. This will normally be a {@link JsonObject}. * @param options options controlling how the document is replaced. See {@link TransactionReplaceOptions} for * details * @return the doc, updated with its new CAS value. For performance a copy is not created and the original doc * object is modified. */ public TransactionGetResult replace(TransactionGetResult doc, Object content, TransactionReplaceOptions options) { return reactive.replace(doc, content, options) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } public TransactionGetResult replace(TransactionGetResult doc, Object content) { return reactive.replace(doc, content, TransactionReplaceOptions.DEFAULT) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Inserts a new document into the specified Couchbase collection. *

* As with {@link #replace}, the insert is staged until the transaction is committed. Due to technical limitations * it is not as possible to completely hide the staged data from the rest of the Couchbase platform, as an empty * document must be created. *

* This staged data effectively locks the document from other transactional writes until the attempt completes * (commits or rolls back). * * @param collection the Couchbase collection in which to insert the doc * @param options options controlling how the document is inserted. See {@link TransactionInsertOptions} for * details * @param id the document's unique ID * @param content the content to insert. Generally this will be a * {@link com.couchbase.client.java.json.JsonObject} * @return the doc, updated with its new CAS value and ID, and converted to a TransactionGetResult */ public TransactionGetResult insert(Collection collection, String id, Object content, TransactionInsertOptions options) { return reactive.insert(collection.reactive(), id, content, options) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } public TransactionGetResult insert(Collection collection, String id, Object content) { return insert(collection, id, content, TransactionInsertOptions.DEFAULT); } /** * Removes the specified doc, using the document's last * {@link TransactionGetResult#cas()}. *

* As with {@link #replace}, the remove is staged until the transaction is committed. That is, the document will * continue to exist, and the rest of the Couchbase platform will continue to see it. *

* This staged data effectively locks the document from other transactional writes until the attempt completes * (commits or rolls back). *

* Note that a remove(String id) method is not possible, as it's necessary to check a provided * TransactionGetResult to determine if the document is involved in another transaction. * * @param doc the doc to be removed */ public void remove(TransactionGetResult doc) { reactive.remove(doc) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Commits the transaction. All staged replaces, inserts and removals will be written. *

* After this, no further operations are permitted on this instance, and they will result in an * IllegalStateException that will, if not caught in the transaction logic, cause the transaction to * fail * with a TransactionFailed exception. */ public void commit() { reactive.commit() .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Defers committing this transaction. *

* The resultant {@link TransactionResult#serialized()} will contain a serialized form of the context for this * transaction, which can be resumed using {@link Transactions#commit} or {@link Transactions#rollback}. */ @Stability.Volatile public void defer() { reactive.defer() .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Rolls back the transaction. All staged replaces, inserts and removals will be removed. The transaction will not * be retried, so this will be the final attempt. *

* After this, no further operations are permitted on this instance, and they will result in an * IllegalStateException that will, if not caught in the transaction logic, cause the transaction to * fail * with a TransactionFailed exception. */ public void rollback() { reactive.rollback() .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Returns the globally unique ID of this attempt, which may be useful for debugging and logging purposes. */ public String attemptId() { return reactive.attemptId(); } /** * Returns the globally unique ID of the overall transaction owning this attempt, which may be useful for debugging * and logging purposes. */ public String transactionId() { return reactive.transactionId(); } /** * Runs a N1QL query and returns the result. *

* All rows are buffered in-memory. The reactive version of this API provides a streaming interface which will not/ *

* @throws CouchbaseException on failure. The application can choose to catch and ignore this error, and the * transaction attempt is allowed to continue. This differs from Key-Value operations, whose failure will * cause the attempt to fail. */ @Stability.Uncommitted public QueryResult query(String statement, TransactionQueryOptions options) { return reactive.queryBlocking(statement, options) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } QueryResult query(Scope scope, String statement, TransactionQueryOptions options, boolean tximplicit) { return reactive.queryBlocking(scope, statement, options, tximplicit) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Calls query() with default options. */ @Stability.Uncommitted public QueryResult query(String statement) { return query(statement, TransactionQueryOptions.queryOptions()); } /** * Runs a N1QL query and returns the result. *

* All rows are buffered in-memory. The reactive version of this API provides a streaming interface which will not. *

* This overload performs a 'scope-level query': that is, one in which a collection may be referenced by name in the * query statement, without needing to specify the full bucket.scope.collection syntax. *

* @throws CouchbaseException on failure. The application can choose to catch and ignore this error, and the * transaction attempt is allowed to continue. This differs from Key-Value operations, whose failure will * cause the attempt to fail. */ @Stability.Uncommitted public QueryResult query(Scope scope, String statement, TransactionQueryOptions options) { return reactive.queryBlocking(scope, statement, options, false) .publishOn(SchedulerUtil.schedulerBlocking) .block(); } /** * Calls query() with default options. *

* This overload performs a 'scope-level query': that is, one in which a collection may be referenced by name in the * query statement, without needing to specify the full bucket.scope.collection syntax. */ @Stability.Uncommitted public QueryResult query(Scope scope, String statement) { return query(scope, statement, TransactionQueryOptions.queryOptions()); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy