Class: KBS::Blackboard::Persistence::RedisStore
- Defined in:
- lib/kbs/blackboard/persistence/redis_store.rb
Instance Attribute Summary collapse
-
#redis ⇒ Object
readonly
Returns the value of attribute redis.
-
#session_id ⇒ Object
readonly
Returns the value of attribute session_id.
Instance Method Summary collapse
- #add_fact(uuid, type, attributes) ⇒ Object
- #clear_session(session_id) ⇒ Object
- #close ⇒ Object
-
#connection ⇒ Object
Redis-specific helper to get connection for MessageQueue/AuditLog.
- #get_fact(uuid) ⇒ Object
- #get_facts(type = nil, pattern = {}) ⇒ Object
-
#initialize(url: 'redis://localhost:6379/0', session_id: nil, redis: nil) ⇒ RedisStore
constructor
A new instance of RedisStore.
- #query_facts(conditions = nil, params = []) ⇒ Object
- #register_knowledge_source(name, description: nil, topics: []) ⇒ Object
- #remove_fact(uuid) ⇒ Object
- #stats ⇒ Object
- #transaction(&block) ⇒ Object
- #update_fact(uuid, attributes) ⇒ Object
- #vacuum ⇒ Object
Constructor Details
#initialize(url: 'redis://localhost:6379/0', session_id: nil, redis: nil) ⇒ RedisStore
14 15 16 17 18 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 14 def initialize(url: 'redis://localhost:6379/0', session_id: nil, redis: nil) @session_id = session_id || SecureRandom.uuid @redis = redis || Redis.new(url: url) @transaction_depth = 0 end |
Instance Attribute Details
#redis ⇒ Object (readonly)
Returns the value of attribute redis.
12 13 14 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 12 def redis @redis end |
#session_id ⇒ Object (readonly)
Returns the value of attribute session_id.
12 13 14 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 12 def session_id @session_id end |
Instance Method Details
#add_fact(uuid, type, attributes) ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 20 def add_fact(uuid, type, attributes) attributes_json = JSON.generate(attributes) = Time.now.to_f @redis.multi do |pipeline| pipeline.hset("fact:#{uuid}", { 'uuid' => uuid, 'type' => type.to_s, 'attributes' => attributes_json, 'session_id' => @session_id, 'created_at' => , 'updated_at' => , 'retracted' => '0' }) # Indexes pipeline.sadd('facts:active', uuid) pipeline.sadd("facts:type:#{type}", uuid) pipeline.sadd("facts:session:#{@session_id}", uuid) if @session_id pipeline.sadd('facts:all', uuid) end end |
#clear_session(session_id) ⇒ Object
134 135 136 137 138 139 140 141 142 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 134 def clear_session(session_id) uuids = @redis.smembers("facts:session:#{session_id}") uuids.each do |uuid| remove_fact(uuid) end @redis.del("facts:session:#{session_id}") end |
#close ⇒ Object
195 196 197 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 195 def close @redis.close if @redis end |
#connection ⇒ Object
Redis-specific helper to get connection for MessageQueue/AuditLog
200 201 202 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 200 def connection @redis end |
#get_fact(uuid) ⇒ Object
74 75 76 77 78 79 80 81 82 83 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 74 def get_fact(uuid) fact_data = @redis.hgetall("fact:#{uuid}") return nil if fact_data.empty? || fact_data['retracted'] == '1' { uuid: fact_data['uuid'], type: fact_data['type'].to_sym, attributes: JSON.parse(fact_data['attributes'], symbolize_names: true) } end |
#get_facts(type = nil, pattern = {}) ⇒ Object
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 85 def get_facts(type = nil, pattern = {}) # Get UUIDs from appropriate index uuids = if type @redis.sinter('facts:active', "facts:type:#{type}") else @redis.smembers('facts:active') end # Fetch and filter facts facts = [] uuids.each do |uuid| fact_data = @redis.hgetall("fact:#{uuid}") next if fact_data.empty? || fact_data['retracted'] == '1' attributes = JSON.parse(fact_data['attributes'], symbolize_names: true) if matches_pattern?(attributes, pattern) facts << { uuid: fact_data['uuid'], type: fact_data['type'].to_sym, attributes: attributes } end end facts end |
#query_facts(conditions = nil, params = []) ⇒ Object
113 114 115 116 117 118 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 113 def query_facts(conditions = nil, params = []) # Redis doesn't support SQL queries # For complex queries, use get_facts with pattern matching # or implement custom Redis Lua scripts get_facts end |
#register_knowledge_source(name, description: nil, topics: []) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 131 132 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 120 def register_knowledge_source(name, description: nil, topics: []) topics_json = JSON.generate(topics) @redis.hset("ks:#{name}", { 'name' => name, 'description' => description, 'topics' => topics_json, 'active' => '1', 'registered_at' => Time.now.to_f }) @redis.sadd('knowledge_sources:active', name) end |
#remove_fact(uuid) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 43 def remove_fact(uuid) fact_data = @redis.hgetall("fact:#{uuid}") return nil if fact_data.empty? || fact_data['retracted'] == '1' type = fact_data['type'].to_sym attributes = JSON.parse(fact_data['attributes'], symbolize_names: true) @redis.multi do |pipeline| pipeline.hset("fact:#{uuid}", 'retracted', '1') pipeline.hset("fact:#{uuid}", 'retracted_at', Time.now.to_f) pipeline.srem('facts:active', uuid) pipeline.srem("facts:type:#{type}", uuid) end { type: type, attributes: attributes } end |
#stats ⇒ Object
168 169 170 171 172 173 174 175 176 177 178 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 168 def stats active_count = @redis.scard('facts:active') total_count = @redis.scard('facts:all') ks_count = @redis.scard('knowledge_sources:active') { total_facts: total_count, active_facts: active_count, knowledge_sources: ks_count } end |
#transaction(&block) ⇒ Object
180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 180 def transaction(&block) @transaction_depth += 1 begin if @transaction_depth == 1 # Redis MULTI/EXEC happens in individual operations # This provides a consistent interface yield else yield end ensure @transaction_depth -= 1 end end |
#update_fact(uuid, attributes) ⇒ Object
60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 60 def update_fact(uuid, attributes) fact_data = @redis.hgetall("fact:#{uuid}") return nil if fact_data.empty? || fact_data['retracted'] == '1' attributes_json = JSON.generate(attributes) @redis.multi do |pipeline| pipeline.hset("fact:#{uuid}", 'attributes', attributes_json) pipeline.hset("fact:#{uuid}", 'updated_at', Time.now.to_f) end fact_data['type'].to_sym end |
#vacuum ⇒ Object
144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/kbs/blackboard/persistence/redis_store.rb', line 144 def vacuum # Remove retracted facts from Redis to free memory all_uuids = @redis.smembers('facts:all') all_uuids.each do |uuid| fact_data = @redis.hgetall("fact:#{uuid}") if fact_data['retracted'] == '1' # Calculate if fact is old enough to remove (e.g., > 30 days) retracted_at = fact_data['retracted_at'].to_f if Time.now.to_f - retracted_at > (30 * 24 * 60 * 60) type = fact_data['type'] session_id = fact_data['session_id'] @redis.multi do |pipeline| pipeline.del("fact:#{uuid}") pipeline.srem('facts:all', uuid) pipeline.srem("facts:type:#{type}", uuid) pipeline.srem("facts:session:#{session_id}", uuid) if session_id end end end end end |