Class: Farce::Transaction::Map

Inherits:
Abstract::ConcurrentMap show all
Defined in:
lib/farce/transaction/map.rb

Overview

A ConcurrentMap that is part of a transaction.

Reads and writes validate the keys they access, allowing concurrent changes to other keys. Size reads validate cardinality without observing contents. Enumeration, keys, getkey, and clear capture and validate the full map. Staged changes are visible through this wrapper and publish only on commit. Key validation compares current values by identity, not per-key write history. Commit captures a full snapshot for maps accessed by key. Changes after that snapshot is captured can still cause the attempt to fail.

Constant Summary

Constants included from MapOperations

Farce::Transaction::MapOperations::READ_HELPERS

Instance Method Summary collapse

Methods included from Unshareable

#initialize, #ractor_shareable?

Methods inherited from Abstract::ConcurrentMap

#[], #[]=, #clear, #compact!, #compact_blank!, #compare_and_set, #compare_keys_by_identity?, #compare_values_by_identity?, #compute, #compute_if_absent, #compute_if_present, #delete, #delete_if, #each, #each_key, #each_value, #fetch, #fetch_or_store, #get, #get_and_set, #getkey, #keep_if, #key?, #keys, #merge!, #merge_pair, #put, #put_if_absent, #reject!, #replace_pair, #reverse_merge!, #select!, #size, #store, #store_if_absent, #swap, #transform_values!, #update, #upsert, #values, #wait_until, #wait_until_changed, #wait_until_match, #wait_until_non_nil, #wait_until_value, #wait_while, #wait_while_match, #wait_while_value

Methods included from Abstract::DuplicableMap

#compact, #compact_blank, #deep_dup, #duplicable?, #except, #flatten, #invert, #merge, #reject, #reverse_merge, #select, #slice, #stringify_keys, #symbolize_keys, #to_proc, #transform_keys, #transform_values, #with_indifferent_access

Methods inherited from Abstract::Map

#[], #[]=, #as_extended_json, #as_json, #assert_valid_keys, #assoc, #bson_type, #clear, #compare_by_identity?, #compare_keys_by_identity?, #compare_values_by_identity?, #deconstruct_keys, #delete, #dig, #each, #each_key, #each_pair, #each_value, #empty?, #fetch, #fetch_values, #getkey, #has_key?, #key, #key?, #keys, #length, #rassoc, #shareable_keys?, #shareable_values?, #size, #store, #store_if_absent, #to_a, #to_bson, #to_bson_normalized_value, #to_cbor, #to_h, #to_hash, #to_json, #to_msgpack, #to_query, #to_s, #value?, #values_at, #weak_keys?, #weak_values?

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Farce::Transaction::Wrapper

Instance Method Details

#delete_pair(key, expected) ⇒ Boolean

Atomically remove a key if its current value matches expected. The configured value-comparison mode determines whether matching uses equality or identity. Missing keys and mismatched values are left unchanged. A failed comparison invalidates the transaction attempt.

Parameters:

  • key (BasicObject) —

    The key to remove.

  • expected (BasicObject) —

    The expected current value.

  • timeout (Numeric, nil) —

    The maximum number of seconds to wait for access.

Returns:

  • (Boolean) —

    Whether the entry was removed. Returns false on timeout.



45
46
47
48
49
50
# File 'lib/farce/transaction/map.rb', line 45

def delete_pair(key, expected)
  removed = modify_entry(key) do |present, value|
    present && values_equal?(value, expected) ? Internal::MAP_DELETE : Internal::MAP_KEEP
  end
  compared(removed)
end

#replace_if_exists(key, replacement, mode: nil) ⇒ BasicObject?

Atomically replace an existing value and return its previous value. An absent key is left unchanged. Existing nil and false values can be replaced.

Parameters:

  • key (BasicObject) —

    The key to update.

  • replacement (BasicObject) —

    The value to store.

  • timeout (Numeric, nil) —

    The maximum number of seconds to wait for access.

  • mode (Symbol, nil) (defaults to: nil) —

    The replacement's transfer mode, or nil to use the default.

Returns:

  • (BasicObject, nil) —

    The previous value, or nil when the key is absent or access timed out.

See Also:



33
34
35
36
37
38
39
40
41
# File 'lib/farce/transaction/map.rb', line 33

def replace_if_exists(key, replacement, mode: nil)
  write do
    canonical = prepare(key)
    next unless @working.key?(canonical)
    previous = @working[canonical]
    store_value(canonical, wrap(replacement, mode:))
    unwrap_stored(previous)
  end
end

#store_if_present(key, mode: nil) {|value| ... } ⇒ BasicObject?

Atomically replace the value associated with a key if it is present. The block receives the current value and should return the new value to store. The block is not called for an absent key. A stored nil is passed to the block.

Parameters:

  • key (BasicObject) —

    The key to update.

  • timeout (Numeric, nil) —

    The maximum number of seconds to wait for access.

  • mode (Symbol, nil) (defaults to: nil) —

    The result's transfer mode, or nil to use the default.

Yields:

  • (value) —

    Called with the current value if the key is present.

Yield Parameters:

  • value (BasicObject) —

    The current value.

Yield Returns:

  • (BasicObject) —

    The new value to store.

Returns:

  • (BasicObject, nil) —

    The newly stored value, or nil if the key was absent or the operation timed out.

Raises:

  • (LocalJumpError) —

    If no block is given.



21
22
23
24
25
26
27
28
29
# File 'lib/farce/transaction/map.rb', line 21

def store_if_present(key, mode: nil)
  require_block!(block_given?)
  write do
    canonical = prepare(key)
    next unless @working.key?(canonical)
    replacement = yield(unwrap_stored(@working[canonical]))
    unwrap_stored(store_value(canonical, wrap(replacement, mode:)))
  end
end