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