Marcin said:
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)
# -
rogress (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,
rogress
if [
rogress, :results, :error, :timeout].include? state
info[:status]=state
info[:stop]=Time.now unless state ==
rogress
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,
rogress].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