• Stars
    star
    284
  • Rank 145,616 (Top 3 %)
  • Language
    Ruby
  • License
    MIT License
  • Created over 11 years ago
  • Updated almost 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

An efficient optionally thread safe LRU Cache

LruRedux Gem Version

An efficient, thread safe LRU cache.

Installation

Add this line to your application's Gemfile:

gem 'lru_redux'

And then execute:

$ bundle

Or install it yourself as:

$ gem install lru_redux

Ruby 1.8 - v0.8.4 is the last compatible release:

gem 'lru_redux', '~> 0.8.4'

Usage

require 'lru_redux'

# non thread safe
cache = LruRedux::Cache.new(100)
cache[:a] = "1"
cache[:b] = "2"

cache.to_a
# [[:b,"2"],[:a,"1"]]
# note the order matters here, last accessed is first

cache[:a] # a pushed to front
# "1"

cache.to_a
# [[:a,"1"],[:b,"2"]]
cache.delete(:a)
cache.each {|k,v| p "#{k} #{v}"}
# b 2

cache.max_size = 200 # cache now stores 200 items
cache.clear # cache has no items

cache.getset(:a){1}
cache.to_a
#[[:a,1]]

# already set so don't call block
cache.getset(:a){99}
cache.to_a
#[[:a,1]]

# for thread safe access, all methods on cache
# are protected with a mutex
cache = LruRedux::ThreadSafeCache.new(100)

TTL Cache

The TTL cache extends the functionality of the LRU cache with a Time To Live eviction strategy. TTL eviction occurs on every access and takes precedence over LRU eviction, meaning a 'live' value will never be evicted over an expired one.

# Timecop is gem that allows us to change Time.now
# and is used for demonstration purposes.
require 'lru_redux'
require 'timecop'

# Create a TTL cache with a size of 100 and TTL of 5 minutes.
# The first argument is the size and
# the second optional argument is the TTL in seconds.
cache = LruRedux::TTL::Cache.new(100, 5 * 60)

Timecop.freeze(Time.now)

cache[:a] = "1"
cache[:b] = "2"

cache.to_a
# => [[:b,"2"],[:a,"1"]]

# Now we advance time 5 min 30 sec into the future.
Timecop.freeze(Time.now + 330)

# And we see that the expired values have been evicted.
cache.to_a
# => []

# The TTL can be updated on a live cache using #ttl=.
# Currently cached items will be evicted under the new TTL.
cache[:a] = "1"
cache[:b] = "2"

Timecop.freeze(Time.now + 330)

cache.ttl = 10 * 60

# Since ttl eviction is triggered by access,
# the items are still cached when the ttl is changed and
# are now under the 10 minute TTL.
cache.to_a
# => [[:b,"2"],[:a,"1"]]

# TTL eviction can be triggered manually with the #expire method.
Timecop.freeze(Time.now + 330)

cache.expire
cache.to_a
# => []

Timecop.return

# The behavior of a TTL cache with the TTL set to `:none`
# is identical to the LRU cache.

cache = LruRedux::TTL::Cache.new(100, :none)

# The TTL argument is optional and defaults to `:none`.
cache = LruRedux::TTL::Cache.new(100)

# A thread safe version is available.
cache = LruRedux::TTL::ThreadSafeCache.new(100, 5 * 60)

Cache Methods

  • #getset Takes a key and block. Will return a value if cached, otherwise will execute the block and cache the resulting value.
  • #fetch Takes a key and optional block. Will return a value if cached, otherwise will execute the block and return the resulting value or return nil if no block is provided.
  • #[] Takes a key. Will return a value if cached, otherwise nil.
  • #[]= Takes a key and value. Will cache the value under the key.
  • #delete Takes a key. Will return the deleted value, otherwise nil.
  • #evict Alias for #delete.
  • #clear Clears the cache. Returns nil.
  • #each Takes a block. Executes the block on each key-value pair in LRU order (most recent first).
  • #to_a Return an array of key-value pairs (arrays) in LRU order (most recent first).
  • #key? Takes a key. Returns true if the key is cached, otherwise false.
  • #has_key? Alias for #key?.
  • #count Return the current number of items stored in the cache.
  • #max_size Returns the current maximum size of the cache.
  • #max_size= Takes a positive number. Changes the current max_size and triggers a resize. Also triggers TTL eviction on the TTL cache.

TTL Cache Specific

  • #ttl Returns the current TTL of the cache.
  • #ttl= Takes :none or a positive number. Changes the current ttl and triggers a TTL eviction.
  • #expire Triggers a TTL eviction.

Benchmarks

see: benchmark directory (a million random lookup / store)

LRU

Ruby 2.2.1
$ ruby ./bench/bench.rb

Rehearsal -------------------------------------------------------------
ThreadSafeLru               4.500000   0.030000   4.530000 (  4.524213)
LRU                         2.250000   0.000000   2.250000 (  2.249670)
LRUCache                    1.720000   0.010000   1.730000 (  1.728243)
LruRedux::Cache             0.960000   0.000000   0.960000 (  0.961292)
LruRedux::ThreadSafeCache   2.180000   0.000000   2.180000 (  2.187714)
--------------------------------------------------- total: 11.650000sec

                                user     system      total        real
ThreadSafeLru               4.390000   0.020000   4.410000 (  4.415703)
LRU                         2.140000   0.010000   2.150000 (  2.149626)
LRUCache                    1.680000   0.010000   1.690000 (  1.688564)
LruRedux::Cache             0.910000   0.000000   0.910000 (  0.913108)
LruRedux::ThreadSafeCache   2.200000   0.010000   2.210000 (  2.212108)
Ruby 2.0.0-p643

Implementation is slightly different for Ruby versions before 2.1 due to a Ruby bug. http://bugs.ruby-lang.org/issues/8312

$ ruby ./bench/bench.rb
Rehearsal -------------------------------------------------------------
ThreadSafeLru               4.790000   0.040000   4.830000 (  4.828370)
LRU                         2.170000   0.010000   2.180000 (  2.180630)
LRUCache                    1.810000   0.000000   1.810000 (  1.814737)
LruRedux::Cache             1.330000   0.010000   1.340000 (  1.325554)
LruRedux::ThreadSafeCache   2.770000   0.000000   2.770000 (  2.777754)
--------------------------------------------------- total: 12.930000sec

                                user     system      total        real
ThreadSafeLru               4.710000   0.060000   4.770000 (  4.773233)
LRU                         2.120000   0.010000   2.130000 (  2.135111)
LRUCache                    1.780000   0.000000   1.780000 (  1.781392)
LruRedux::Cache             1.190000   0.010000   1.200000 (  1.201908)
LruRedux::ThreadSafeCache   2.650000   0.010000   2.660000 (  2.652580)

TTL

Ruby 2.2.1
$ ruby ./bench/bench_ttl.rb
Rehearsal -----------------------------------------------------------------------
FastCache                             6.240000   0.070000   6.310000 (  6.302569)
LruRedux::TTL::Cache                  4.700000   0.010000   4.710000 (  4.712858)
LruRedux::TTL::ThreadSafeCache        6.300000   0.010000   6.310000 (  6.319032)
LruRedux::TTL::Cache (TTL disabled)   2.460000   0.010000   2.470000 (  2.470629)
------------------------------------------------------------- total: 19.800000sec

                                          user     system      total        real
FastCache                             6.470000   0.070000   6.540000 (  6.536193)
LruRedux::TTL::Cache                  4.640000   0.010000   4.650000 (  4.661793)
LruRedux::TTL::ThreadSafeCache        6.310000   0.020000   6.330000 (  6.328840)
LruRedux::TTL::Cache (TTL disabled)   2.440000   0.000000   2.440000 (  2.446269)

Other Caches

This is a list of the caches that are used in the benchmarks.

LRU

LRUCache

ThreadSafeLru

FastCache

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Add some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

Changelog

version 1.1.0 - 30-Mar-2015

  • New: TTL cache added. This cache is LRU like with the addition of time-based eviction. Check the Usage -> TTL Cache section in README.md for details.

version 1.0.0 - 26-Mar-2015

  • Ruby Support: Ruby 1.9+ is now required by LruRedux. If you need to use LruRedux in Ruby 1.8, please specify gem version 0.8.4 in your Gemfile. v0.8.4 is the last 1.8 compatible release and included a number of fixes and performance improvements for the Ruby 1.8 implementation. @Seberius
  • Perf: improve performance in Ruby 2.1+ on the MRI @Seberius

version 0.8.4 - 20-Feb-2015

  • Fix: regression of ThreadSafeCache under JRuby 1.7 @Seberius

version 0.8.3 - 20-Feb-2015

  • Perf: improve ThreadSafeCache performance @Seberius

version 0.8.2 - 16-Feb-2015

  • Perf: use #size instead of #count when checking length @Seberius
  • Fix: Cache could grow beyond its size in Ruby 1.8 @Seberius
  • Fix: #each could deadlock in Ruby 1.8 @Seberius

version 0.8.1 - 7-Sep-2013

  • Fix #each implementation
  • Fix deadlocks with ThreadSafeCache
  • Version jump is because its been used in production for quite a while now

version 0.0.6 - 24-April-2013

  • Fix bug in getset, overflow was not returning the yeilded val

version 0.0.5 - 23-April-2013

  • Added getset and fetch
  • Optimised implementation so it 20-30% faster on Ruby 1.9+

version 0.0.4 - 23-April-2013

  • Initial version

More Repositories

1

memory_profiler

memory_profiler for ruby
Ruby
1,659
star
2

MiniProfiler

A simple but effective mini-profiler for ASP.NET MVC, ASP.NET and Ruby.
1,050
star
3

fast_blank

Ruby
610
star
4

flamegraph

Flamegraph profiling support for Ruby 2.0
HTML
382
star
5

graphite_docker

docker container for graphite
Python
165
star
6

redismux

A simple redis multiplexer
Go
54
star
7

allocator_bench

bench of various memory allocators
Ruby
51
star
8

So-Slow

Stack Overflow creative commons database importer
C#
41
star
9

blog

samsaffron.com blog plugin for Discourse
Ruby
37
star
10

cpu-analyzer

C#
36
star
11

dotfiles

various dotfiles I use
Vim Script
31
star
12

fast_stack

Ruby
19
star
13

react-native-key-pair

Objective-C
19
star
14

performance

my personal playground for various perf stuff
Ruby
12
star
15

tvdb-scraper

Scrapes TV metadata from thetvdb
Ruby
9
star
16

youtube-home

a toy I use to disable youtube requires ubiquity router
Ruby
8
star
17

media-library

.Net library for management of media
C#
7
star
18

DataExplorerPG

DataExplorerPG
C#
6
star
19

discourse-ansible

ansible script for setting up discourse from scratch on ubuntu
Ruby
5
star
20

autotest-shoes-gui

A simple GUI for autotest written in shoes
Ruby
5
star
21

simplestorageengine

A simple storage engine for .Net apps supporting active record
C#
4
star
22

ruby-bench-play

Ruby
4
star
23

Media-Browser

Media Browser Git Fork
C#
4
star
24

logviewer

A simple GUI logviewer for rails and ruby
Ruby
2
star
25

discourse_public_import

A tool to import all public posts on discourse
Ruby
2
star
26

super-ssh

A tiny script that help keep ssh tunnels up, similar to autossh
2
star
27

stacktrace

An extension for Ruby that provides with class and method information in the backtrace
Ruby
1
star
28

discourse-solarized

discourse solarized color scheme
1
star
29

brotli-test

A container to test brotli dynamic compression
HTML
1
star
30

discourse-roboto-theme

roboto theme demo
CSS
1
star
31

mysqldump-x-restore

Automatically exported from code.google.com/p/mysqldump-x-restore
XSLT
1
star
32

discourse-nginx-performance-report

Ruby
1
star
33

discourse-dev-benchmark

Ruby
1
star
34

mini_locale

Ruby
1
star
35

bench_web

quick benchmarking tool for web sites
Ruby
1
star