diff --git a/utils/lru/README b/utils/lru/README new file mode 100644 index 000000000..288189e3e --- /dev/null +++ b/utils/lru/README @@ -0,0 +1,13 @@ +The test-lru.rb program can be used in order to check the behavior of the +Redis approximated LRU algorithm against the theoretical output of true +LRU algorithm. + +In order to use the program you need to recompile Redis setting the define +REDIS_LRU_CLOCK_RESOLUTION to 1, by editing redis.h. +This allows to execute the program in a fast way since the 1 ms resolution +is enough for all the objects to have a different enough time stamp during +the test. + +The program is executed like this: + + ruby test-lru.rb > /tmp/lru.html diff --git a/utils/lru/test-lru.rb b/utils/lru/test-lru.rb new file mode 100644 index 000000000..d4b0f88cf --- /dev/null +++ b/utils/lru/test-lru.rb @@ -0,0 +1,112 @@ +require 'rubygems' +require 'redis' + +r = Redis.new +r.config("SET","maxmemory","2000000") +r.config("SET","maxmemory-policy","allkeys-lru") +r.config("SET","maxmemory-samples",5) +r.config("RESETSTAT") +r.flushall + +puts < + + +
+EOF
+
+# Fill
+oldsize = r.dbsize
+id = 0
+while true
+    id += 1
+    r.set(id,"foo")
+    newsize = r.dbsize
+    break if newsize == oldsize
+    oldsize = newsize
+end
+
+inserted = r.dbsize
+first_set_max_id = id
+puts "#{r.dbsize} keys inserted"
+
+# Access keys sequencially
+
+puts "Access keys sequencially"
+(1..first_set_max_id).each{|id|
+    r.get(id)
+#    sleep 0.001
+}
+
+# Insert more 50% keys. We expect that the new keys
+half = inserted/2
+puts "Insert enough keys to evict half the keys we inserted"
+add = 0
+while true
+    add += 1
+    id += 1
+    r.set(id,"foo")
+    break if r.info['evicted_keys'].to_i >= half
+end
+
+puts "#{add} additional keys added."
+puts "#{r.dbsize} keys in DB"
+
+# Check if evicted keys respect LRU
+# We consider errors from 1 to N progressively more serious as they violate
+# more the access pattern.
+
+errors = 0
+e = 1
+edecr = 1.0/(first_set_max_id/2)
+(1..(first_set_max_id/2)).each{|id|
+    e -= edecr if e > 0
+    e = 0 if e < 0
+    if r.exists(id)
+        errors += e
+    end
+}
+
+puts "#{errors} errors!"
+puts "
" + +# Generate the graphical representation +(1..id).each{|id| + # Mark first set and added items in a different way. + c = "box" + if id <= first_set_max_id + c << " old" + else + c << " new" + end + + # Add class if exists + c << " ex" if r.exists(id) + puts "
" +} + +# Close HTML page + +puts < + +EOF