Class: ThreadSafe::MriCacheBackend

Inherits:
NonConcurrentCacheBackend show all
Defined in:
lib/thread_safe/mri_cache_backend.rb

Constant Summary collapse

WRITE_LOCK =

We can get away with a single global write lock (instead of a per-instance one) because of the GVL/green threads.

The previous implementation used `Thread.critical` on 1.8 MRI to implement the 4 composed atomic operations (`put_if_absent`, `replace_pair`, `replace_if_exists`, `delete_pair`) this however doesn't work for `compute_if_absent` because on 1.8 the Mutex class is itself implemented via `Thread.critical` and a call to `Mutex#lock` does not restore the previous `Thread.critical` value (thus any synchronisation clears the `Thread.critical` flag and we loose control). This poses a problem as the provided block might use synchronisation on its own.

NOTE: a neat idea of writing a c-ext to manually perform atomic put_if_absent, while relying on Ruby not releasing a GVL while calling a c-ext will not work because of the potentially Ruby implemented `#hash` and `#eql?` key methods.

Mutex.new

Instance Method Summary collapse

Methods inherited from NonConcurrentCacheBackend

#[], #each_pair, #get_or_default, #initialize, #key?, #size, #value?

Constructor Details

This class inherits a constructor from ThreadSafe::NonConcurrentCacheBackend

Instance Method Details

#[]=(key, value) ⇒ Object


14
15
16
# File 'lib/thread_safe/mri_cache_backend.rb', line 14

def []=(key, value)
  WRITE_LOCK.synchronize { super }
end

#clearObject


58
59
60
# File 'lib/thread_safe/mri_cache_backend.rb', line 58

def clear
  WRITE_LOCK.synchronize { super }
end

#compute(key) ⇒ Object


30
31
32
# File 'lib/thread_safe/mri_cache_backend.rb', line 30

def compute(key)
  WRITE_LOCK.synchronize { super }
end

#compute_if_absent(key) ⇒ Object


18
19
20
21
22
23
24
# File 'lib/thread_safe/mri_cache_backend.rb', line 18

def compute_if_absent(key)
  if stored_value = _get(key) # fast non-blocking path for the most likely case
    stored_value
  else
    WRITE_LOCK.synchronize { super }
  end
end

#compute_if_present(key) ⇒ Object


26
27
28
# File 'lib/thread_safe/mri_cache_backend.rb', line 26

def compute_if_present(key)
  WRITE_LOCK.synchronize { super }
end

#delete(key) ⇒ Object


50
51
52
# File 'lib/thread_safe/mri_cache_backend.rb', line 50

def delete(key)
  WRITE_LOCK.synchronize { super }
end

#delete_pair(key, value) ⇒ Object


54
55
56
# File 'lib/thread_safe/mri_cache_backend.rb', line 54

def delete_pair(key, value)
  WRITE_LOCK.synchronize { super }
end

#get_and_set(key, value) ⇒ Object


46
47
48
# File 'lib/thread_safe/mri_cache_backend.rb', line 46

def get_and_set(key, value)
  WRITE_LOCK.synchronize { super }
end

#merge_pair(key, value) ⇒ Object


34
35
36
# File 'lib/thread_safe/mri_cache_backend.rb', line 34

def merge_pair(key, value)
  WRITE_LOCK.synchronize { super }
end

#replace_if_exists(key, new_value) ⇒ Object


42
43
44
# File 'lib/thread_safe/mri_cache_backend.rb', line 42

def replace_if_exists(key, new_value)
  WRITE_LOCK.synchronize { super }
end

#replace_pair(key, old_value, new_value) ⇒ Object


38
39
40
# File 'lib/thread_safe/mri_cache_backend.rb', line 38

def replace_pair(key, old_value, new_value)
  WRITE_LOCK.synchronize { super }
end