module RailsConnector # This module provides advances auto-invalidating caching mechanism for storing obj data. # # To keep it up-to-date it's caches and changes should be updated periodically # It's changes should be updated every time a new workspace data has been fetched. # It's caches should be updated every time a new obj data has been fetched. module ContentStateCaching class << self # How deep should a content state chain be inspected. Default depth is 20. attr_accessor :cache_lookup_depth # At which lookup depth to copy a hit found in an ancestor content state # to the current content state's cache. Default depth is 5. attr_accessor :cache_replication_depth # Creates a new content state for given workspace with given ancetor and returns it. def store_content_state(workspace_data) ContentState.create(content_state_id: workspace_data.to_content_state_id, changes: workspace_data.changes, from_content_state_id: workspace_data.from_content_state_id) end # Fetches last known content state id for a given workspace id. # Returns nil if there is no content state for that workspace. def find_content_state_id(workspace_id) CmsCacheStorage.read_workspace_content_state_id(workspace_id) end # Stores current content state id for workspace with given id. def store_content_state_id(workspace_id, content_state_id) CmsCacheStorage.write_workspace_content_state_id(workspace_id, content_state_id) end # Updates caches with data from given workspace. # Should be called every time a new OBJ data has been fetched. def store_obj_data(workspace_data, index, key, data) content_state = workspace_data.content_state content_state.save_obj_data(index, key, data) if content_state end # Fetches up-to-date obj data for given workspace, index and key. # Returns nil if no up-to-date data found. def find_obj_data(workspace_data, index, key) return unless current_content_state = workspace_data.content_state if index == 'permalink' current_content_state.find_obj_data(index, key) else visitor = ContentStateVisitor.new(current_content_state) cache_lookup_depth.times do |depth| return unless content_state = visitor.visit_next if hit = content_state.find_obj_data(index, key) visitor.visited_except_current.each { |cs| return if cs.has_changes_for?(index, key, hit) } current_content_state.save_obj_data(index, key, hit) if depth >= cache_replication_depth return hit end end nil end end end self.cache_replication_depth = 5 self.cache_lookup_depth = 20 end end