Class: Kameleoon::Managers::Tracking::ConcurrentVisitorTrackingRegistry
- Inherits:
-
Object
- Object
- Kameleoon::Managers::Tracking::ConcurrentVisitorTrackingRegistry
- Defined in:
- lib/kameleoon/managers/tracking/visitor_tracking_registry.rb
Overview
Visitor codes waiting for a tracking request, in a Hash used as an insertion-ordered set.
Lock-free on the hot path (MRI): add is a single Hash#[]=, which the GVL makes atomic (String keys hash
in C, so no Ruby code runs inside it), and request threads never block on the registry. The Hash is never
swapped out; extract removes with Hash#shift (O(1), oldest first) under a lock that only serializes
extractors, so a concurrently added code is either returned now or kept for the next extraction, never
lost. Nothing here iterates the live Hash: an add during iteration would raise in the request thread.
Other engines run threads in parallel and take the lock on add as well: JRuby's Hash raises
ConcurrencyError on unsynchronized concurrent writes; TruffleRuby's shared collections are thread-safe,
but the lock-free path has not been measured there.
Constant Summary collapse
- LIMITED_EXTRACTION_THRESHOLD_COEFFICIENT =
2- REMOVAL_FACTOR =
0.8
- UNLIMITED_EXTRACTION =
2**62
- LOCK_FREE_ADD =
(RUBY_ENGINE == 'ruby')
Instance Method Summary collapse
- #add(visitor_code) ⇒ Object
- #add_all(visitor_codes) ⇒ Object
-
#extract(limit = UNLIMITED_EXTRACTION) ⇒ Object
Removes and returns visitor codes, oldest first: all of them while the registry holds no more than
limitcodes and fewer than twice the extraction limit, otherwisemin(limit, extraction_limit). -
#initialize(visitor_manager, storage_limit = 1_000_000, extraction_limit = 20_000) ⇒ ConcurrentVisitorTrackingRegistry
constructor
A new instance of ConcurrentVisitorTrackingRegistry.
-
#visitors ⇒ Object
Test purpose only.
Constructor Details
#initialize(visitor_manager, storage_limit = 1_000_000, extraction_limit = 20_000) ⇒ ConcurrentVisitorTrackingRegistry
Returns a new instance of ConcurrentVisitorTrackingRegistry.
22 23 24 25 26 27 28 |
# File 'lib/kameleoon/managers/tracking/visitor_tracking_registry.rb', line 22 def initialize(visitor_manager, storage_limit = 1_000_000, extraction_limit = 20_000) @visitor_manager = visitor_manager @storage_limit = storage_limit @extraction_limit = extraction_limit @visitors = {} @extract_mutex = Mutex.new end |
Instance Method Details
#add(visitor_code) ⇒ Object
31 32 33 |
# File 'lib/kameleoon/managers/tracking/visitor_tracking_registry.rb', line 31 def add(visitor_code) @visitors[visitor_code] = true end |
#add_all(visitor_codes) ⇒ Object
35 36 37 38 |
# File 'lib/kameleoon/managers/tracking/visitor_tracking_registry.rb', line 35 def add_all(visitor_codes) visitor_codes.each { |vc| @visitors[vc] = true } erase_to_storage_limit if @visitors.size > @storage_limit end |
#extract(limit = UNLIMITED_EXTRACTION) ⇒ Object
Removes and returns visitor codes, oldest first: all of them while the registry holds no more than
limit codes and fewer than twice the extraction limit, otherwise min(limit, extraction_limit).
52 53 54 |
# File 'lib/kameleoon/managers/tracking/visitor_tracking_registry.rb', line 52 def extract(limit = UNLIMITED_EXTRACTION) @extract_mutex.synchronize { shift_visitors(extraction_count(@visitors.size, limit)) } end |
#visitors ⇒ Object
Test purpose only
57 58 59 |
# File 'lib/kameleoon/managers/tracking/visitor_tracking_registry.rb', line 57 def visitors @visitors.keys end |