Class: ThreadSafe::MriCacheBackend

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

Constant Summary

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)

Constructor Details

This class inherits a constructor from ThreadSafe::NonConcurrentCacheBackend

Instance Method Details

- (Object) []=(key, value)



21
22
23
# File 'lib/thread_safe/mri_cache_backend.rb', line 21

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

- (Object) clear



65
66
67
# File 'lib/thread_safe/mri_cache_backend.rb', line 65

def clear
  WRITE_LOCK.synchronize { super }
end

- (Object) compute(key)



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

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

- (Object) compute_if_absent(key)



25
26
27
28
29
30
31
# File 'lib/thread_safe/mri_cache_backend.rb', line 25

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

- (Object) compute_if_present(key)



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

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

- (Object) delete(key)



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

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

- (Object) delete_pair(key, value)



61
62
63
# File 'lib/thread_safe/mri_cache_backend.rb', line 61

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

- (Object) get_and_set(key, value)



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

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

- (Object) merge_pair(key, value)



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

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

- (Object) replace_if_exists(key, new_value)



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

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

- (Object) replace_pair(key, old_value, new_value)



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

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