Transaction

Structin corefastly 0.13.1View source
pub struct Transaction { /* private fields */ }

A cache transaction initiated by Transaction::lookup().

Transactions coordinate between concurrent actions on the same cache key, incorporating concepts of request collapsing and revalidation, though at a lower level that does not automatically interpret HTTP semantics.

Request collapsing

If there are multiple concurrent calls to Transaction::lookup() for the same item and that item is not present, just one of the callers will be instructed to insert the item into the cache as part of the transaction. The other callers will block until the metadata for the item has been inserted, and can then begin streaming its contents out of the cache at the same time that the inserting caller streams them into the cache. To avoid blocking while waiting for the object to be provided, clients can use TransactionLookupBuilder::execute_async().

Revalidation

Similarly, if an item is usable but stale, and multiple callers attempt a Transaction::lookup() concurrently, they will all be given access to the stale item, but only one will be designated to perform an asynchronous update (or insertion) to freshen the item in the cache.

Example

Users of the transactional API should at minimum anticipate lookups that are obligated to insert an item into the cache, and lookups which are not. If the stale-while-revalidate parameter is set for cached items, the user should also distinguish between the insertion and revalidation cases.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
const MAX_AGE: Duration = Duration::from_secs(3600);
// perform the lookup
let lookup_tx = Transaction::lookup(CacheKey::from_static(b"my_key"))
.execute()?;
if let Some(found) = lookup_tx.found() {
// a cached item was found; we use it now even though it might be stale,
// and we'll revalidate it below
use_found_item(&found);
}
// now we need to handle the "must insert" and "must update" cases
if lookup_tx.must_insert_or_update() {
if let Some(stale_found) = lookup_tx.found() {
// a cached item was found and used above, and now we need to perform
// revalidation
let revalidation_contents = build_contents();
if should_replace(&stale_found, &revalidation_contents) {
// use `insert` to replace the previous object
let mut writer = lookup_tx
.insert(MAX_AGE)
.surrogate_keys(["my_key"])
.known_length(revalidation_contents.len() as u64)
.execute()?;
writer.write_all(revalidation_contents)?;
writer.finish()?;
} else {
// otherwise update the stale object's metadata
lookup_tx
.update(MAX_AGE)
.surrogate_keys(["my_key"])
.execute()?;
}
} else {
// a cached item was not found, and we've been chosen to insert it
let contents = build_contents();
let (mut writer, found) = lookup_tx
.insert(MAX_AGE)
.surrogate_keys(["my_key"])
.known_length(contents.len() as u64)
// stream back the object so we can use it after inserting
.execute_and_stream_back()?;
writer.write_all(contents)?;
writer.finish()?;
// now we can use the item we just inserted
use_found_item(&found);
}
}

Methods

cancel_insert_or_update

View source
fn cancel_insert_or_update(&self) -> Result<(), CacheError>

Cancels the obligation for this transaction client to insert or update a cache item.

If there are concurrent transactional lookups that were blocked waiting on this client to provide the item, one of them will be chosen to be unblocked and given the Transaction::must_insert_or_update() obligation.

This method should only be called when Transaction::must_insert_or_update() is true; otherwise, a CacheError::InvalidOperation will be returned.

Parameters

self: &Self

Returns

fn found(&self) -> Option<Found>

Returns a Found object for this cache item, if one is available.

Even if an object is found, the cache item might be stale and require updating. Use Transaction::must_insert_or_update() to determine whether this transaction client is expected to update the cached item.

Parameters

self: &Self

Returns

fn insert(self, max_age: Duration) -> TransactionInsertBuilder

Returns a TransactionInsertBuilder that will perform a transactional cache insertion.

This method should only be called when Transaction::must_insert_or_update() is true; otherwise, a CacheError::InvalidOperation will be returned when attempting to execute the insertion.

Parameters

self: Self
max_age: Duration

Returns

Returns a TransactionLookupBuilder that will perform a transactional cache lookup.

See Transaction for details and an example.

Parameters

key: CacheKey

Returns

must_insert

View source
fn must_insert(&self) -> bool

Returns true if a usable cached item was not found, and this transaction client is expected to insert one.

Use Transaction::insert() to insert the cache item, or Transaction::cancel_insert_or_update() to exit the transaction without providing an item.

Parameters

self: &Self

Returns

bool

must_insert_or_update

View source
fn must_insert_or_update(&self) -> bool

Returns true if a fresh cache item was not found, and this transaction client is expected to insert a new item or update a stale item.

Use:

Parameters

self: &Self

Returns

bool
fn update(self, max_age: Duration) -> TransactionUpdateBuilder

Returns a TransactionUpdateBuilder that will perform a transactional cache update.

Updating an item freshens it by updating its metadata, e.g. its age, without changing the object itself.

This method should only be called when Transaction::must_insert_or_update() is true and the item is found (i.e. Transaction::found() is non-empty). Otherwise, a CacheError::InvalidOperation will be returned when attempting to execute the update.

The method consumes the transaction. Call Transaction::found() before this method if subsequent access to the stale cached item is needed.

Important note: the TransactionUpdateBuilder will replace all of the configuration in the underlying cache item; if any configuration is not set on the builder, it will revert to the default value. So, for example, if a cached item previously had some surrogate keys set, and you want to retain them, you must call TransactionUpdateBuilder::surrogate_keys() with the desired keys. Most configuration is available in the Found object.

Note: the above behavior is likely to be replaced with defaulting the builder to the existing configuration, making it easier to retain the configuration by default. This change will be noted in a future changelog.

Parameters

self: Self
max_age: Duration

Returns

Auto trait implementations

Blanket implementations