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