programmatix
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # IMPORTANT This doc is no longer maintained. Please see current version on https://github.com/couchbaselabs/couchbase-transactions-specs/ # Couchbase Transactions API Copyright (c) 2020 Couchbase, Inc. # Lambda The application provides their transaction logic inside a lambda/callback. This a) gives us control over the error handling and retry strategy, e.g. we’re free to retry their logic as often as required, and can tweak this in the future. And b) frees them from the same. Implementors should implement something close to this in their languages (full details are below, this is just to give an overview of how things look to the user - it is also now no longer relevant with ExtSDKIntegration): ```java Transactions transactions = Transactions.create(cluster, TransactionConfigBuilder.create() .durabilityLevel(TransactionDurabilityLevel.MAJORITY) .build()); try { transactions.run((ctx) -> { // Inserting a doc: String docId = "test-id"; ctx.insert(coll, docId, JsonObject.create()); // Getting documents: Optional<TransactionGetResult> docOpt = ctx.getOptional(coll, docId); TransactionGetResult doc = ctx.get(collection, docId); // Replacing a doc: TransactionGetResult anotherDoc = ctx.getOrError(coll, "anotherDoc"); JsonObject content = anotherDoc.contentAs(JsonObject.class); content.put("transactions", "are awesome"); ctx.replace(anotherDoc, content); // Removing a doc: TransactionGetResult yetAnotherDoc = ctx.getOrError(coll, "yetAnotherDoc"); ctx.remove(yetAnotherDoc); ctx.commit(); }); } catch (TransactionCommitAmbiguous e) { for (LogDefer err : e.result().log().logs()) { // Optionally, log the result } } catch (TransactionFailed e) { for (LogDefer err : e.result().log().logs()) { // Optionally, log the result } } ``` In ExtSDKIntegration this changes to: ```java // This initial config section is Java-specific ClusterEnvironment env = ClusterEnvironment.builder() .transactionsConfig( TransactionsConfig.durabilityLevel(MAJORITY)); Cluster cluster = Cluster.connect(seedNodes(), ClusterOptions .clusterOptions(authenticator()) .environment(env)); try { cluster.transactions().run((ctx) -> { // The lambda internals are the same, except // ctx.commit(), ctx.rollback() and ctx.getOptional() are removed. }); } catch (TransactionCommitAmbiguousException e) { // Optionally, log the result e.logs().forEach(log -> logger.warn(log)); } catch (TransactionFailedException e) { // Optionally, log the result e.logs().forEach(log -> logger.warn(log)); } ``` ExtSDKIntegration integrates the transactions API into the SDKs. This document specifies both ExtSDKIntegration and what existed before, rather than splitting them into separate documents, as the most common use-case currently is implementors needing to compare the changes. The design document for ExtSDKIntegration is [here](https://docs.google.com/document/d/16Ldq3JxzwybRr2d3l1gUuwdMarmIjZRvHtmYRb6bl1w/edit#). Some changes required for ExtSDKIntegration that are not spelt out elsewhere in this document are: * Package names will likely change to reflect the underlying SDK. * # Platform Specifics Java-esque syntax and naming conventions will be used to define the API. It is desirable that all implementations closely resemble each other, but the implementer should aim to strike a balance between adherence to the specification, and achieving a native-feeling API in the target language. For example, where Java uses `TransactionConfig`, C++ may use `transaction::config`. Languages are free to implement non-blocking variants also. The appearance of this will be highly platform-dependent: implementers should aim to achieve a non-blocking API as close to the specification as possible, with the constraints of the platform. See the Java version’s reactive API as an example. Note, there are items in the public Java API that are not in the specification below. The specification should be used as the reference. Used below will be `Optional`, representing a one-or-none monad, and `Duration`. The implementer should use the most appropriate platform-dependent tool for these. # Transaction instantiation Before ExtSDKIntegration: The `Transactions` object is a transactions factory, and is the starting point for the API. There should only be one per application, as it may be doing expensive tasks such as maintaining thread pools, or background threads doing cleanup. If more than one is created, the library should detect this and log a warning at Warn level. However, it will allow the operation to continue to support some advanced cases where the application is fully aware of what it’s doing (e.g. for testing). ### Transactions.create() This only applies before ExtSDKIntegration. ```java static Transactions create(Cluster cluster, [TransactionConfig config]) ``` Creates a Transactions object. |Parameter|Required|Description| |---------|--------|-----------| |Cluster|Yes|Required for the distributed background cleanup process| |Config|No|Configuration options| ### cluster.transactions() From ExtSDKIntegration, this is how transactions are accessed. ```java cluster.transactions().run((ctx) -> { // Transaction logic }); ``` `cluster.transactions()` still returns a `Transactions` object with the same methods as specified in this document. But the `Transactions` object differs in key ways: * It no longer needs to be a singleton. This is left implementation dependent: the implementation is free to create a `Transactions` object on each `cluster.transactions()` call if it wishes, though a singleton will likely be more performant. * The key detail is that cleanup must have singleton behaviours. E.g. if a new `Transactions` object is created from the same `cluster`, it must not create a new set of cleanup threads. It is suggested, but left as an implementation detail, that there is a singleton `TransactionsCleanup` object per-`Cluster`. * The life-cycle of that `Transactions` object is now bound to the `Cluster` it's created from. There is no need for an explicit `Transactions.close()` method anymore. It, and more importantly `TransactionsCleanup`, are destroyed when the `Cluster` is. The main way we expect users to use the new API is this: ```java cluster.transactions().run((ctx) -> { // Transaction logic }); ``` They can also take the `Transactions` object and pass that around: ```java Transactions transactions = cluster.transactions(); transactions.run((ctx) -> { // Transaction logic }); ``` ### Transactions.config() ```java // ExtSDKIntegration // Removed: no need to expose the TransactionsConfig. // Non-ExtSDKIntegration TransactionConfigBuilder config() ``` Return the config used to construct this. ### Transactions.run() ```java // ExtSDKIntegration TransactionResult run(Consumer<TransactionAttemptContext> transactionLogic, [TransactionOptions options]) // Non-ExtSDKIntegration TransactionResult run(Consumer<AttemptContext> transactionLogic, [PerTransactionConfig perConfig]) ``` Starts and runs a single transaction. Blocking (but implementations are free to implement a non-blocking version too, such as Java’s reactive API). |Parameter|Required|Description| |---------|--------|-----------| |transactionLogic|Yes|A lambda, that takes an AttemptContext / TransactionAttemptContext, and uses this to perform transactional operations.| |perConfig / options|No|Configuration options that override the global config| ### Transactions.commit() Only needed if ExtDeferredCommit is implemented - which it should not be at this time. ```java TransactionResult commit(TransactionSerializedContext serialized, [PerTransactionConfig perConfig]) ``` Commits a previously deferred transaction. Deferred transactions will be described in more detail later, but essentially, are a mechanism to pause (defer) a transaction just before the commit point, for future commit. `@Volatile`: deferred transactions should be marked as a volatile feature. We cannot guarantee the API will not change at this point. |Parameter|Required|Description| |---------|--------|-----------| |serialized|Yes|A serialized blob representing the deferred transaction.| |perConfig|No|Configuration options that override the Transactions-level config| ### Transactions.rollback() Only needed if ExtDeferredCommit is implemented - which it should not be at this time. ```java TransactionResult rollback(TransactionSerializedContext serialized, [PerTransactionConfig perConfig]) ``` Rolls back a previously deferred transaction. `@Volatile`: deferred transactions should be marked as a volatile feature. We cannot guarantee the API will not change at this point. |Parameter|Required|Description| |---------|--------|-----------| |serialized|Yes|Serialized blob representing the deferred transaction.| |perConfig|No|Configuration options that override the Transactions-level config| ### Transactions.close() Do not add this in ExtSDKIntegration. ```java void close() ``` Closes the Transactions object, along with any associated resources. Resource management and ownership tend to be highly platform-specific, and the implementor should use the pattern and naming most appropriate to their platform. For example, C++ may want to use an RAII destructor, while Java implements @Autoclosable. ### query Required for ExtSingleQuery, before the SDK integration. If ExtSDKIntegration is also implemented, then these are not required. ExtSingleQuery is instead supported through an option on the standard SDK3 `QueryOptions` on `cluster.query()` and `scope.query()`. ```java SingleQueryTransactionResult query(String statement) SingleQueryTransactionResult query(String statement, SingleQueryTransactionConfig config) SingleQueryTransactionResult query(Scope scope, String statement) SingleQueryTransactionResult query(Scope scope, String statement, SingleQueryTransactionConfig config) ``` Performs a N1QL query inside the transaction. Languages that do not support overloads can provide four methods with platform-suitable naming for review. |Parameter|Description| |---------|-----------| |scope|Used for scope-level queries.| |statement|The N1QL query.| |config|Configuration options.| # Configuration In ExtSDKIntegration, configuration happens at the point of configuring the Cluster. In Java this looks like: ```java ClusterEnvironment env = ClusterEnvironment.builder() .transactionsConfig( TransactionsConfig.durabilityLevel(MAJORITY)); Cluster cluster = Cluster.connect(seedNodes(), ClusterOptions .clusterOptions(authenticator()) .environment(env)); ``` Before ExtSDKIntegration, a `TransactionConfig` is passed to `Transactions.create()`. ## Builder pattern Many SDKs use a fluent builder pattern for their options classes, and this should be followed for all such classes in this document if so. For example: ```java // ExtSDKIntegration TransactionsConfig.Builder timeout(Duration timeout) // Non-ExtSDKIntegration TransactionConfigBuilder expirationTime(Duration expirationTime) ``` ## TransactionConfig Under ExtSDKIntegration it was renamed to `TransactionsConfig`. The options are listed here in the approximate order of level of expected usage. |Option|Default|Description| |------|-------|-----------| |expirationTime / timeout | 15 seconds|Sets the maximum time that transactions created by this Transactions object can run for, before expiring.<br><br>Note that expiration is not guaranteed to be followed precisely.<br>For example, if the application were to do a long blocking operation inside the lambda (which should be avoided), then expiration can only trigger after this finishes.<br><br>Similarly, if the transaction attempts a key-value operation close to the expiration time, and that key-value operation times out, then the expiration time may be exceeded.<br><br>Renamed to `timeout` in ExtSDKIntegration.| |durabilityLevel|MAJORITY|The writes of all transactions created by this object will be performed with this durability setting.<br><br>TransactionDurabilityLevel is an enum with these values: NONE, MAJORITY, MAJORITY_AND_PERSIST_TO_ACTIVE, and PERSIST_TO_MAJORITY.<br><br>In ExtSDKIntegration, use the standard SDK3 `DurabilityLevel` enum instead.<br><br>NONE is there, but is not a supported setting. There are no atomicity guarantees if this is used: a node failover can cause vbucket rollback and an atomicity failure.| |keyValueTimeout|unspecified (KV writes will default to the SDK’s defaults)|The default timeout used for all KV writes.<br><br>Do not add in ExtSDKIntegration. In Rage we will soon be completely reworking how KV timeouts work, which will remove the need for this parameter (which already has limited use due to transaction retries).| |unstagingMode|platform-specific|This is only required if the implementation supports both ExtMemoryOptUnstaging and ExtTimeOptUnstaging and wants to allow the user to select the mode.<br><br>It should be marked the platform-specific version of @Stability.Volatile.| |metadataCollection|Collection / TransactionKeyspace|Only required if implementation supports ExtCustomMetadataCollection.<br><br>It specifies the collection to use for any metadata (ATR and client-record) access.<br><br>ExtSDKIntegration: it is a `TransactionKeyspace` rather than a `Collection`. Specifying this also adds it to the cleanup set (and when anything is added to the cleanup set, cleanup is started.)| |queryConfig|TransactionQueryConfig / TransactionsQueryConfig|Only required if implementation supports ExtQuery.| ## TransactionQueryConfig This was renamed under ExtSDKIntegration to `TransactionsQueryConfig`. It should be implemented as a nested object inside `TransactionsConfig` / `TransactionConfig`: ```java // ExtSDKIntegration TransactionsConfig queryConfig(TransactionsQueryConfig queryConfig) // Non-ExtSDKIntegration TransactionConfig queryConfig(TransactionQueryConfig queryConfig) ``` ## Cleanup options In ExtSDKIntegration these are moved to a separate object `TransactionsCleanupConfig`. ```java ClusterEnvironment.Builder .transactionsConfig( TransactionsConfig.Builder .cleanupConfig(TransactionsCleanupConfig.Builder // Existing options .cleanupWindow(Duration.ofSeconds(30)) .cleanupClientAttempts(false) .cleanupLostAttempts(false) // New options .addCollection(TransactionKeyspace.create("aBucket", DEFAULT_SCOPE, "aCollection")))); ``` Before ExtSDKIntegration, these options exist in `TransactionConfig`. |Option|Default|Description| |------|-------|-----------| |cleanupClientAttempts|true|Controls where any transaction attempts made by this client are automatically removed.<br><br>The usual implementation would be to start a background thread, that processes a queue of transactions created by this client that should be cleaned up after a certain time. E.g., removing the record for the attempt from the ATR.| |cleanupLostAttempts|true|Controls whether a background process is created to cleanup any 'lost' transaction attempts.| |cleanupWindow|60 seconds|Each client that has cleanupLostAttempts(true) enabled, will be participating in the distributed cleanup process. This involves checking all ATRs every cleanup window, and this parameter controls the length of that window.<br><br>This is a conservative default that will not put significant load on the cluster, while finding any lost transactions in a reasonable time. Decreasing the window will ensure that lost transactions are found more swiftly, at the cost of more frequent ATR polling.| |addCollection|TransactionKeyspace|Added in ExtSDKIntegration.<br><br>Adds a collection to the cleanup set, which will also start cleanup immediately.| # TransactionKeyspace Added for ExtSDKIntegration, as we need to be able to specify collections without having the Collection created yet. It should look very similar to the SDK's implementation of `EventingFunctionKeyspace`. These constructor methods are possible: ```java TransactionKeyspace.create("aBucket") TransactionKeyspace.create("aBucket", "aScope") TransactionKeyspace.create("aBucket", DEFAULT_SCOPE, "aCollection") ``` # TransactionQueryConfig Required for ExtQuery. Under ExtSDKIntegration it was renamed `TransactionsQueryConfig`. |Option|Type|Description| |------|-------|-----------| |scanConsistency|QueryScanConsistency|Sets the default scan consistency to use for all query statements in the transaction. Default is unset (and query will default to REQUEST_PLUS).| # PerTransactionConfig This was renamed under ExtSDKIntegration to `TransactionOptions`. Allows the global `TransactionConfig` settings to be overridden for this transaction. See [TransactionConfig](#TransactionConfig) for the definition of these settings. These settings are currently supported: * durabilityLevel * unstagingMode (only if multiple unstaging modes are supported by the implementation) ExtQuery adds the first three of these fields, ExtSDKIntegration the fourth: |Field|Type|ExtSDKIntegration| |------|-------|----| |expirationTime|Duration|Rename to "timeout"| |keyValueTimeout|Duration|Remove| |queryConfig|PerTransactionQueryConfig|Remove| |metadataCollection|Collection (not TransactionKeyspace)|Added. Was not present before ExtSDKIntegration.| # PerTransactionQueryConfig Required for ExtQuery. Allows the global TransactionQueryConfigBuilder settings to be overridden for this transaction. Currently only scanConsistency is present. Removed in ExtSDKIntegration. # AttemptContext Renamed in ExtSDKIntegration to `TransactionAttemptContext`. Provides all operations for an individual transaction, to allow it to read and mutate documents. Note, there are no throws specifications for any of these, as the application should not be doing any try-catch handling of any of these operations. Any operation could theorectically throw any exception (though in reality it can only throw a `ErrorWrapper`), the exceptions may change in the future, and the application is explicitly required to not make any assumptions on the current or future exception behaviour. This is required to allow the transactions library to transparently retry the transaction lambda when needed. Some exceptions to those above rules exist as of ExtQuery and ExtSDKIntegration. ## Content handling A number of operations need to specify content to insert, replace, etc. Content is described as `Object` in this doc as per the Java implementation, but the exact mechanism for supplying content will depend on the platform (e.g. an Object, a generic `T`, an `interface {}`, a dictionary...). The method for supplying content should resemble the underlying SDK. ## getOptional ```java Optional<TransactionGetResult> getOptional(Collection collection, String id) ``` Gets a document. If the document does not exist, it will return `Optional.empty` rather than failing the transaction. |Parameter|Required|Description| |---------|--------|-----------| |collection|Yes|The document's collection| |id|Yes|The document’s key| Removed in ExtSDKIntegration - replaced with ctx.get() raising a catchable `DocumentNotFoundException`. ## get ```java TransactionGetResult get(Collection collection, String id, [TransactionGetOptions options]) ``` Gets a document. The application can use this or [getOptional](#getOptional) depending on whether it is expecting the document to exist or not. If the document does not exist, the transaction will auto-rollback then raise a `TransactionFailed` error to the application, with root cause `DocumentNotFoundException`. |Parameter|Required|Description| |---------|--------|-----------| |collection|Yes|The document's collection| |id|Yes|The document’s key| |options|No|Added in ExtBinarySupport. See below for details| Under ExtSDKIntegration, the implementation may raise a `DocumentNotFoundException`, which the user may catch. `TransactionGetOptions` was added in ExtBinarySupport and contains one option: a `Transcoder transcoder` that is not-set/null by default, and works similarly to the same option in non-transactional `GetOptions`. Its exact handling is detailed below under [TransactionGetResult](#TransactionGetResult). ## replace ```java TransactionGetResult replace(TransactionGetResult doc, Object content, [TransactionReplaceOptions options]) ``` Mutates a document previously fetched inside the same transaction. This mutation will be staged in the document’s xattrs. If the document does not exist, the transaction will auto-rollback then raise a `TransactionFailed` error to the application, with root cause `DocumentNotFoundException`. Returns the inserted document in the form of a TransactionGetResult. |Parameter|Required|Description| |---------|--------|-----------| |doc|Yes|The result of a previous call to get or getOptional, inside the same transaction attempt| |content|Yes|The new content to stage| |options|No|Added in ExtBinarySupport. See below for details| ## getReplicaFromPreferredServerGroup Added in ExtReplicaFromPreferredGroup. ```java TransactionGetResult getReplicaFromPreferredServerGroup(Collection collection, String id, [TransactionGetReplicaOptions options]) ``` Gets a document, fetching it preferentially from a preferred server group (which is set by the user elsewhere). The method can only throw `DocumentUnretrievableException` or `TransactionOperationFailed`. Other transaction specs detail when these occur. |Parameter|Required|Description| |---------|--------|-----------| |collection|Yes|The document's collection| |id|Yes|The document’s key| |options|No|See below for details| `TransactionGetReplicaOptions` contains one option: a `Transcoder transcoder` that is not-set/null by default, and works similarly to the same option in non-transactional `GetOptions`. Its exact handling is detailed below under [TransactionGetResult](#TransactionGetResult). If the SDK does not yet supported `ExtBinarySupport` then it does not need to add this options block. Note that `ReadPreference` from SDK-RFC 78 is explicitly not added here, as the method name indicates the preference. ### Transcoder `TransactionReplaceOptions` was added with ExtBinarySupport and contains one option: a `Transcoder transcoder` that is not-set/null by default, and works similarly to the same option in non-transactional `ReplaceOptions`. That is, if present, the `content` will be passed to the `Transcoder`, and the resulting encoded byte array and int32 flags, passed down to the transactions internals. ## insert ```java TransactionGetResult insert(Collection collection, String id, Object content, [TransactionInsertOptions] options) ``` If the document already exists, the transaction will auto-rollback then raise a `TransactionFailed` error to the application, with root cause `DocumentExistsException`. Returns the inserted document in the form of a TransactionGetResult. |Parameter|Required|Description| |---------|--------|-----------| |collection|Yes|The collection to insert the document in| |id|Yes|The document’s key| |content|Yes|The new content to stage| |options|No|Added in ExtBinarySupport. See below for details| ### Transcoder ExtBinaryInsert: See the same section under [replace](#replace) above - transcoding for insert works the same way. ## remove ```java void remove(TransactionGetResult doc) ``` Removes a document previously fetched inside the same transaction. If the document does not exist, the transaction will auto-rollback then raise a TransactionFailed error to the application, with root cause DocumentNotFoundException. |Parameter|Required|Description| |---------|--------|-----------| |doc|Yes|The result of a previous call to get or getOptional, inside the same transaction attempt| ## commit ```java void commit() ``` Commits the transaction. This is completely optional. If control flow reaches the end of the lambda with no thrown exceptions, commit will be performed automatically. Removed in ExtSDKIntegration, as it is redundant. ## rollback ```java void rollback() ``` Rolls back the transaction. No error will be returned to the application if the app-rollback succeeds. It is rare to require this. In general, if the application discovers it needs to app-rollback the transaction, it is probably an error state, and better modelled by throwing a custom exception. This will result in the attempt being rolled back, and a `TransactionFailed` raised to the application with the custom exception as the root cause. This permits the application to confirm that the transaction in fact rolled back, and why, which this API call does not provide. Removed in ExtSDKIntegration, as it is redundant. ## query Required for ExtQuery. ```java TransactionQueryResult query(String statement) TransactionQueryResult query(String statement, TransactionQueryOptions options) TransactionQueryResult query(Scope scope, String statement) TransactionQueryResult query(Scope scope, String statement, TransactionQueryOptions options) ``` Performs a N1QL query inside the transaction. Languages that do not support overloads can provide four methods with platform-suitable naming for review. |Parameter|Description| |---------|-----------| |scope|Used for scope-level queries.| |statement|The N1QL query.| |options|Configuration options.| Note that under the original ExtQuery implementation a QueryResult was returned. This was changed to a TransactionQueryResult under [CBD-4602](https://issues.couchbase.com/browse/CBD-4602), to allow implementations to have a streaming QueryResult and a non-streaming TransactionQueryResult. TransactionQueryResult is identical to QueryResult except it presents a non-streaming interface. This is left implementation-dependent. ## defer ```java void defer() ``` Defers committing the transaction. The returned TransactionResult contains a serialized() method that contains a serialized blob representing this transaction, which may be later committed. @Volatile: as with all methods related to deferred commits, this must be marked volatile. Only required for ExtDeferredCommit, which should not be implemented. ## logger ```java TransactionLogger logger() ``` Returns the logger used by this. Optional, but helpful for debugging as it allows the application to write its own log into the transaction logs. # TransactionGetResult Represents a document fetched from Couchbase, along with additional transactional data (such as whether the transaction is currently involved in another transaction). It’s intended to be similar to SDK3’s `GetResult`. ExtBinarySupport: to be more explicit on that, internally the `TransactionGetResult` should hold an array of bytes for the content, and an int32 for the document's flags. ## id ```java String id() ``` Returns the id of the document. ## contentAs ```java T contentAs<T>() ``` Works exactly like SDK3: convert the document’s content into something else. Note the content can have come from either the document’s body, or the staged mutation in the xattr. Uses the `JsonSerializer` configured on the SDK, as per ExtSerialization. #### ExtBinarySupport If the user specified a `Transcoder` via `TransactionGetOptions`, then pass that transcoder the content byte array and the document's flags, and return the deserialized result to the user. This should work the same way as the rest of the SDK, so see the [SDK3 Transcoders and Serializers RFC](https://github.com/couchbaselabs/sdk-rfcs/blob/master/rfc/0055-serializers-transcoders.md) for more detail. The one exception is that, that unlike other SDK operations, we do not use the default `Transcoder` specified at the `Cluster` level. This is to preserve compatibility with existing applications. If a `Transcoder` has not been specified via `TransactionGetOptions`, then continue with the existing `contentAs` logic (e.g. use the `JsonSerializer` configured at the `Cluster` level). ## Internals There are various transactional and document metadata required, including the document's CAS and any contents of the "txn" xattr. These should be stored in the `TransactionGetResult` but not accessible publically. The exact mechanism for this is platform dependent. The platform equivalent of @Stability.Internal can be used. # TransactionResult Represents the result of a transaction, which can contain multiple attempts. This is returned directly from `Transactions.run()` or `cluster.transactions().run()`, and is also contained in a `TransactionFailed` exception (the latter is no longer the case in ExtSDKIntegration). ## log ```java TransactionLogger log() ``` Provides an in-memory log containing all log related to this transaction. It is optional but strongly recommended. It allows: * Easier debugging of intermittent test failures on CI, as FIT will automatically dump the log of the last transaction to stdout. * We can have verbose-but-cheap logging. Transactions are complex and verbose logging has proved essential while debugging the Java implementation over 3+ years. * The application can easily log this full verbose logging only on failed transactions. ## transactionId ```java String transactionId() ``` The id of the transaction. ## ~~attempts~~ Deprecated/removed in CBD-3757. Do not add it to new implementations, and remove if present while implementing ExtSDKIntegration. ## ~~mutationState~~ Now removed under CBD-3802. This should not be present in any API that is not GA already (e.g. just Java). Remove if present while implementing ExtSDKIntegration. ## ~~mutationTokens~~ Now removed under CBD-3802. This should not be present in any API that is not GA already (e.g. just Java). Remove if present while implementing ExtSDKIntegration. ## unstagingComplete ```java boolean unstagingComplete() ``` Returns true iff the transaction reached the COMPLETED state. ## serialized ```java Optional<TransactionSerializedContext> serialized() ``` Only required for ExtDeferredCommit, which should not be implemented. Returns a serialized representation of a deferred transaction, suitable for later commit or app-rollback. This will only be present if the application called AttemptContext.defer() on the transaction. @Volatile: as with everything to do with deferred commits, this must be marked volatile. # ~~TransactionAttempt~~ Deprecated/removed in CBD-3757. Do not add it to new implementations, and remove if present while implementing ExtSDKIntegration # Exceptions For backwards-compatibility reasons, all exceptions have to derive from `TransactionFailed` / `TransactionFailedException`. Only the exceptions in this section may be raised to the application. ExtSDKIntegration: all exceptions are renamed to be suffixed with `Exception`, and derive from `CouchbaseException`, as per SDK3. ## TransactionFailed The transaction failed, pre-commit. It is unambiguously not committed and none of its changes are visible. It contains the underlying reason (exception) as a root cause, represented in the most platform-appropriate way (e.g. for Java it is `err.getCause()``). It also has a method: ```java TransactionResult result() ``` This returns the result object of the transaction, allowing (most usefully) access to the logs. In ExtSDKIntegration this is replaced (except in Go, which GA-ed before this decision) with these methods: ``` List[TransactionLogMessage] logs() String transactionId() ``` ## TransactionExpired The transaction expired pre-commit. It is unambiguously not commited, none of its changes are visible. ## TransactionCommitAmbiguous It is ambiguous whether the transaction committed. See the main design document for a detailed discussion of why this error is required. # TransactionSerializedContext Only required for ExtDeferredCommit, which should not be implemented. ## encodeAsString ```java String encodeAsString() ``` Returns the serialized blob in String format. ## encodeAsBytes ```java byte[] encodeAsBytes() ``` Returns the serialized blob in byte[] format. # TransactionQueryOptions This provides a subset of the standard SDK3 `QueryOptions`: * parameters * scanConsistency * flexIndex * serializer * clientContextId * scanWait * scanCap * pipelineBatch * pipelineCap * readonly * adhoc * raw * profile Anything not on that list is explicitly not included. This includes parentSpan (the transaction can configure this automatically itself), timeout (will be ignored by query), and retryStrategy (this is controlled by the transactions library). # Single query transactions This is the part of the API that changes most radically under ExtSDKIntegration, as it's integrated into the regular query API: ```java // ExtSDKIntegration QueryResult qr = cluster.query("INSERT...", queryOptions() .asTransaction()) QueryResult qr = scope.query("INSERT...", queryOptions() .asTransaction(SingleQueryTransactionOptions. .durabilityLevel(DurabilityLevel.MAJORITY)) .timeout(Duration.ofSeconds(360))) // Non-ExtSDKIntegration SingleQueryTransactionResult qr = transactions.query("INSERT...") SingleQueryTransactionResult qr = transactions.query(scope, "INSERT...", SingleQueryTransactionConfigBuilder.create() .expirationTime(Duration.ofSeconds(360)) .durabilityLevel(TransactionDurabilityLevel.MAJORITY) .build()) ``` # SingleQueryTransactionConfig Required for ExtSingleQuery. It is still required in ExtSDKIntegration, though its name has changed and most fields are removed. Allows a single query transaction to be configured, with these options: |Option|Type|Description| |------|-----------|---| |queryOptions|TransactionQueryOptions|Configures the single query.<br><br>Removed under ExtSDKIntegration, as we use the options from `QueryOptions`.| |durabilityLevel|TransactionDurabilityLevel / DurabilityLevel|Overrides the default durability level.<br><br>Under ExtSDKIntegration, TransactionDurabilityLevel is replaced with the regular SDK DurabilityLevel.| |expirationTime|Duration|Overrides the default expiration time.<br><br>Removed in ExtSDKIntegration, as we can use the `timeout` from `QueryOptions`.| # SingleQueryTransactionResult Required for ExtSingleQuery, before the SDK integration. If ExtSDKIntegration is also implemented, then this is not required. The result, from the API perspective, is a standard SDK3 `QueryResult`. |Option|Description| |------|-----------| |log: TransactionLogger|Buffered in-memory log from the transaction.| |queryResult: QueryResult|Result of the query.| |unstagingComplete: Boolean|Same as with `TransactionResult`.|

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully