require "large_object_store/version" module LargeObjectStore def self.wrap(store) RailsWrapper.new(store) end class RailsWrapper attr_reader :store LIMIT = 1024**2 - 100 def initialize(store) @store = store end def write(key, value, options = {}) value = Marshal.dump(value) # store number of pages pages = (value.size / LIMIT.to_f).ceil if pages == 1 @store.write("#{key}_0", value, options) else @store.write("#{key}_0", pages, options) # store object page = 1 loop do slice = value.slice!(0, LIMIT) break if slice.size == 0 @store.write("#{key}_#{page}", slice, options) page += 1 end end true end def read(key) # read pages pages = @store.read("#{key}_0") return if pages.nil? data = if pages.is_a?(String) pages else # read sliced data keys = Array.new(pages).each_with_index.map{|_,i| "#{key}_#{i+1}" } slices = @store.read_multi(*keys).values return nil if slices.compact.size < pages slices.join("") end Marshal.load(data) end def fetch(key, options={}) value = read(key) return value unless value.nil? value = yield write(key, value, options) value end def delete(key) @store.delete("#{key}_0") end end end