go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gae/filter/txnBuf/doc.go (about)

     1  // Copyright 2015 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package txnBuf contains a transaction buffer filter for the datastore
    16  // service.
    17  //
    18  // By default, datastore transactions take a snapshot of the entity group as
    19  // soon as you Get or Put into it. All subsequent Get (and query) operations
    20  // reflect the state of the ORIGINAL transaction snapshot, regardless of any
    21  // Put/Delete operations you've done since the beginning of the transaction.
    22  //
    23  // If you've installed this transaction buffer, then:
    24  //
    25  //   - All mutations will be reflected in all read operations (see LIMITATIONS).
    26  //     Without the buffer, read operations always observe the state of the
    27  //     entity group(s) at the time that the transaction started.
    28  //
    29  //   - All mutation operations will be buffered until the close of the
    30  //     transaction. This can help reduce the transaction size, and thus avoid
    31  //     the transaction size limit (currently 10MB). Multiple puts to the same
    32  //     entity will not increase the transaction size multiple times.
    33  //
    34  //   - Transactions inside of an existing transaction will add to their outer
    35  //     transaction if they don't cause the outer transaction to exceed its
    36  //     size budget.
    37  //
    38  //   - If an inner transaction would cause the OUTERMOST transaction to exceed
    39  //     the appengine-imposed 10MB transaction size limit, an error will be
    40  //     returned from the inner transaction, instead of adding it into the
    41  //     outermost transaction. This only applies to the first level of inner
    42  //     transactions, and does not apply to recursive transactions. The reason
    43  //     for this is that it's entirely feasible for inner transactions to
    44  //     temporarially exceed the limit, but still only commit an outer
    45  //     transaction which is under the limit. An example of this would be having
    46  //     one inner-inner transaction add a lot of large entities and then having
    47  //     a subsequent inner-inner transaction delete some of those entities.
    48  //
    49  // LIMITATIONS (only inside of a transaction)
    50  //
    51  //   - KeysOnly/Projection/Count queries are supported, but may incur additional
    52  //     costs.
    53  //
    54  //     These query types are implemented via projection queries, but will
    55  //     project all order-by fields in addition to any specified in the original
    56  //     query.
    57  //
    58  //   - Distinct Projection queries do all 'distinct' deduplication in-memory.
    59  //     This could make them substantially more expensive than their native
    60  //     equivalent.
    61  //
    62  //   - Metadata entities (e.g. `__entity_group__`) will reflect their values as
    63  //     they were at the beginning of the transaction, and will not increment
    64  //     as you write inside of the transaction.
    65  //
    66  //   - Query cursors are not supported. Since the cursor format for the
    67  //     in-memory datastore implementation isn't compatible with the production
    68  //     cursors, it would be pretty tricky to make it so that cursors were
    69  //     viable outside the transaction as well as inside of it while also having
    70  //     it accurately reflect the 'merged' query results.
    71  //
    72  //   - No parallel access* to datastore while in a transaction; all nested
    73  //     operations are serialized. This is done for simplicity and correctness.
    74  //
    75  //   - The exception is that callbacks inside of
    76  //     a Run/GetMulti/DeleteMulti/PutMulti query MAY read/write the current
    77  //     transaction. Modifications to the datastore during query executions will
    78  //     not affect the query results (e.g. the query has snapshot consistency
    79  //     from the moment that it begins iteration). Note, however, that datastore
    80  //     operations within the callback are still synchronized. This behavior is
    81  //     so that the user is not forced to buffer all of the query results before
    82  //     doing work with them, but can treat the query like a stream of events,
    83  //     if they so choose.
    84  //
    85  //   - The changing of namespace inside of a transaction is undefined... This is
    86  //     just generally a terrible idea anyway, but I thought it was worth
    87  //     mentioning.
    88  //
    89  //   - Currently, the soft transactions are not directly accessible using the
    90  //     CurrentTransaction interface; it returns the wrapped datastore's
    91  //     transaction. While this is still correct, it could definitely be made
    92  //     more useful by adding transaction buffer metadata to the returned
    93  //     object.
    94  package txnBuf