Marcin Raczkowski wrote: > why don't you try Gemstone or other object-oriented databases? > > besides, memcache isn't THAT much faster then database, it's faster > becouse it can store objects in memory, but if you need queries it > looses all it's advantages. > > greets > > here's simple object oriented DB i wrote ages ago, just throw out state machine stuff and have phun, searching is done in ruby and really easy. it took me one day if i remember correctly so that should be indication of time you'd need to make simple ODB # Module responsible for handling requests informations # # Information status: # - :waiting (waiting for server response) # - :progress (server reported progress) # - :results (server returned results) # - :error (j.w) # - :timeout (request timed out) # - :collect - to be garbage collected (right now for debuging purposes) module Informations # default time to live of message (used when expire is set to :ttl) attr_accessor :default_ttl # default timeout - time betwen ANY actions sent by server attr_accessor :default_timeout # use garbage collecting? attr_accessor :gc def init(ttl=30, timeout=30, gc=true) @gc = gc @default_ttl = ttl @default_timeout = timeout @informations={} end # creates new informations about request, id is request id, # hash should contain additional informations (the'll be merged) def new_info(id, hash) #hash=hash.dup #hash.delete(:data) info={} info[:id]=id info[:status]=:waiting info[:timeout]=@default_timeout info[:last_action]=info[:start]=Time.now info[:expire]=:new info[:ttl]=@default_ttl info.merge! hash @informations[id] = info end # information state machine # checks message status - and takes care of checking state transitions # if transition is wrong it's ignored (no exception is rised!!) # # new info is returned def change_status(info, state) case info[:status] when :waiting, :progress if [:progress, :results, :error, :timeout].include? state info[:status]=state info[:stop]=Time.now unless state == :progress info[:last_action]=Time.now end when :results, :error, :timeout if state == :collect info[:status]=state info[:last_action]=Time.now end end info end # checks if message timed out def timeout?(info) change_status(info, :timeout) if ([:wait, :progress].include? info[:status]) && (Time.now > info[:last_action] + info[:timeout]) end # finds information with id # # takes care of marking msg, as timed out/ to be collected # returns info def find(id) self.timeout?(@informations[id]) begin info = @informations[id].dup #return nil if info[:state]==:collect # don't return expired infos if info[:expire]==:first @gc ? change_status(@informations[id], :collect) : @informations.delete(id) end if (info[:expire]==:ttl) && (Time.now < info[:last_action] + info[:ttl]) @gc ? change_status(@informations[id], :collect) : @informations.delete(id) end rescue Exception info=nil end #info[:last_action]=Time.now preventing expire ? info end # finds all message matching criteria block # or checks if :server_id and :name provided in hash match # # block should return true if information should be returned # # Examples: # find_all({:name=>"actions", :server_id=>"121516136171356151"}) # find_all() {|i| i[:last_action] > Time.now-60 } # returns all informations that state changed minute or less ago # find_all() {|i| i[:status]==:error} # returns all messages that returned errors # gc! if find_all() {|i| i[:status]==:collect}.size > 1000 # clears old messages when there's more then 1000 of them def find_all(hash={}) res = [] @informations.each_pair { |k,v| if block_given? res << self.find(k) if yield(v.dup) else catch(:no_match) { # add more here!! [:server_id, :name].each { |x| throw(:no_match) if hash[x] && hash[x]!=v[x] } res << self.find(k) } end } res.empty? ? nil : res end # clears all messages marked for collection def gc! @informations.each_pair { |k,v| @informations.delete(k) if v[:status]==:collect } end end