Permalink
Browse files

playing...rufus-tokyo ffi

  • Loading branch information...
1 parent 683bb8b commit 35dd48ca4a7a1e6ac5fc057fa8b8ca5563baabbc @nofxx committed Jun 26, 2009
Showing with 209 additions and 5 deletions.
  1. +1 −0 VERSION
  2. +35 −0 benchmark/tokyo_store.rb
  3. +130 −0 lib/tokyo_store.rb
  4. +6 −2 spec/spec_helper.rb
  5. +37 −3 spec/tokyo_store_spec.rb
View
1 VERSION
@@ -0,0 +1 @@
+0.0.1
View
35 benchmark/tokyo_store.rb
@@ -0,0 +1,35 @@
+#
+#
+require 'rubygems'
+require 'active_support'
+$LOAD_PATH.unshift(File.dirname(__FILE__))
+$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
+require 'tokyo_store'
+#include TokyoCabinet
+
+@tokyo = ActiveSupport::Cache.lookup_store :tokyo_store, "localhost"
+@memca = ActiveSupport::Cache.lookup_store :mem_cache_store, "localhost:11211"
+
+# # # Read & Write
+Benchmark.bmbm do |b|
+ b.report("Tokyo#write") { 100_000.times { |i| @tokyo.write i.to_s, "x" }}
+ b.report("Tokyo#read") { 100_000.times { |i| @tokyo.read i.to_s }}
+end
+
+Benchmark.bmbm do |b|
+ b.report("Memca#write") { 100_000.times { |i| @memca.write i.to_s, "x" }}
+ b.report("Memca#read") { 100_000.times { |i| @memca.read i.to_s }}
+end
+
+
+
+# # Read & Write
+# Benchmark.bmbm do |b|
+# b.report("Tokyo#write") { 100.times { |j| Thread.new { 10_000.times { |i| @tokyo.write "#{j}-#{i}", "x" }}}}
+# b.report("Tokyo#read") { 100.times { |j| Thread.new { 10_000.times { |i| @tokyo.read "#{j}-#{i}" }}}}
+# end
+
+# Benchmark.bmbm do |b|
+# b.report("Memca#write") { 100.times { |j| Thread.new { 10_000.times { |i| @memca.write "#{j}-#{i}", "x" }}}}
+# b.report("Memca#read") { 100.times { |j| Thread.new { 10_000.times { |i| @memca.read "#{j}-#{i}" }}}}
+# end
View
130 lib/tokyo_store.rb
@@ -0,0 +1,130 @@
+require 'rufus/tokyo/tyrant'
+# require 'tokyocabinet'
+
+module ActiveSupport
+ module Cache
+
+ # A cache store implementation which stores data in Tokyo Cabinet
+ #
+ # Special features:
+ # - Clustering and load balancing. TODO
+ # - Time-based expiry support. TODO (Lua)
+ # - Per-request in memory cache for all communication with the Tokyo server(s).
+ class TokyoStore < Store
+
+ def self.build_tokyo(*dbs)
+ dbs = dbs.flatten
+ options = dbs.extract_options!
+ dbs = ["localhost"] if dbs.empty?
+ Rufus::Tokyo::Tyrant.new(dbs[0], 45001)
+ #hdb = HDB.new
+ # if !hdb.open(dbs[0], HDB::OWRITER | HDB::OCREAT)
+ # ecode = hdb.ecode
+ # STDERR.printf("open error: %s\n", hdb.errmsg(ecode))
+ # end
+ # hdb
+ end
+
+ # Creates a new TokyoStore object, with the given tyrant server
+ # addresses. Each address is either a host name, or a host-with-port string
+ # in the form of "host_name:port". For example:
+ #
+ # ActiveSupport::Cache::TokyoStore.new("localhost", "server-downstairs.localnetwork:8229")
+ #
+ # If no addresses are specified, then TokyoStore will connect to
+ # localhost port 45001 (the default memcached port).
+ def initialize(*dbs)
+ if dbs.first.respond_to?(:get)
+ @data = dbs.first
+ else
+ @data = self.class.build_tokyo(*dbs)
+ end
+
+ extend Strategy::LocalCache
+ end
+
+ # Reads multiple keys from the cache.
+ def read_multi(*keys)
+ #TODO @data.get_multi keys
+ end
+
+ def read(key, options = nil) # :nodoc:
+ super
+ @data[key]
+ # if str = @data.get(key)
+ # Marshal.load str
+ # else
+ # STDERR.printf("get error: %s\n", @data.errmsg(@data.ecode))
+ # end
+ # logger.error("TokyoError (#{e}): #{e.message}")
+ # nil
+ end
+
+ # Writes a value to the cache.
+ #
+ # Possible options:
+ # - +:unless_exist+ - set to true if you don't want to update the cache
+ # if the key is already set.
+ # - +:expires_in+ - the number of seconds that this value may stay in
+ # the cache. See ActiveSupport::Cache::Store#write for an example.
+ def write(key, value, options = nil)
+ super
+ method = options && options[:unless_exist] ? :add : :set
+ # memcache-client will break the connection if you send it an integer
+ # in raw mode, so we convert it to a string to be sure it continues working.
+ value = value.to_s if raw?(options)
+ value = Marshal.dump value # if value.instance_of? Hash
+ @data[key] = value
+ ###response = @data.put(key, value) || STDERR.printf("get error: %s\n", @data.errmsg(@data.ecode))#, expires_in(options), raw?(options))
+ # logger.error("TokyoError (#{e}): #{e.message}")
+ # false
+ end
+
+ def delete(key, options = nil) # :nodoc:
+ super
+ !@data[key] = nil #, expires_in(options))
+ end
+
+ def exist?(key, options = nil) # :nodoc:
+ # Doesn't call super, cause exist? in memcache is in fact a read
+ # But who cares? Reading is very fast anyway
+ # Local cache is checked first, if it doesn't know then memcache itself is read from
+ !read(key, options).nil?
+ end
+
+ def increment(key, amount = 1) # :nodoc:
+ log("incrementing", key, amount)
+ # TODO
+ end
+
+ def decrement(key, amount = 1) # :nodoc:
+ log("decrement", key, amount)
+ #TODO
+ end
+
+ def delete_matched(matcher, options = nil) # :nodoc:
+ #TODO
+ end
+
+ def clear
+ @data.flush_all
+ end
+
+ def stats
+ @data.stats
+ end
+
+ private
+ def expires_in(options)
+ (options && options[:expires_in]) || 0
+ end
+
+ def raw?(options)
+ options && options[:raw]
+ end
+
+
+ end
+
+ end
+end
View
8 spec/spec_helper.rb
@@ -1,8 +1,12 @@
require 'rubygems'
-require 'bacon'
+#require 'mocha'
+require 'active_support'
+require 'spec'
$LOAD_PATH.unshift(File.dirname(__FILE__))
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
require 'tokyo_store'
+include TokyoCabinet
+Spec::Runner.configure do |config|
-Bacon.summary_on_exit
+end
View
40 spec/tokyo_store_spec.rb
@@ -1,7 +1,41 @@
-require 'spec_helper'
+require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
describe "TokyoStore" do
- it "fails" do
- should.flunk "hey buddy, you should probably rename this file and start specing for real"
+ it "should store fragment cache" do
+ HDB.should_receive(:new).and_return(@mock_hdb = mock("HDB"))
+ @mock_hdb.should_receive(:open).with('data.tch', 6).and_return(true)
+ store = ActiveSupport::Cache.lookup_store :tokyo_store, "data.tch"
+ store.should be_kind_of ActiveSupport::Cache::TokyoStore
end
+
+ it "should fail" do
+ tokyo = HDB.new
+ tokyo.open('data.tch')
+ HDB.should_not_receive(:new)
+ store = ActiveSupport::Cache.lookup_store :tokyo_store, tokyo
+ store.should be_kind_of ActiveSupport::Cache::TokyoStore
+ end
+
+ describe "Similar" do
+
+ before(:all) do
+ @cache = ActiveSupport::Cache::TokyoStore.new 'data.tcb'
+ end
+
+ it "test_should_read_and_write_strings" do
+ @cache.write('foo', 'bar')
+ @cache.read('foo').should eql('bar')
+ end
+
+ it "test_should_read_and_write_hash" do
+ @cache.write('foo', {:a => "b"})
+ @cache.read('foo').should eql({:a => "b"})
+ end
+
+ it "test_should_read_and_write_hash" do
+ @cache.write('foo', {:a => "b", :c => "d"})
+ @cache.read('foo').should eql({:a => "b", :c => "d"})
+ end
+ end
+
end

0 comments on commit 35dd48c

Please sign in to comment.