diff --git a/src/dodb.cr b/src/dodb.cr index 52f791a..72a91e7 100644 --- a/src/dodb.cr +++ b/src/dodb.cr @@ -1,4 +1,5 @@ require "file_utils" require "json" +require "./fifo.cr" # FIFO class to implement a cache policy. require "./dodb/*" # Databases and indexes (basic indexes, partitions, tags, etc.). diff --git a/src/dodb/storage/cached.cr b/src/dodb/storage/cached.cr index ea799c1..86fd660 100644 --- a/src/dodb/storage/cached.cr +++ b/src/dodb/storage/cached.cr @@ -57,19 +57,18 @@ class DODB::Storage::Cached(V) < DODB::Storage(V) end end - # Getting data from the hash in RAM. + # Gets data from the hash in RAM. def []?(key : Int32) : V? - @data[key] - rescue e - # FIXME: rescues any error the same way. - return nil + self[key] rescue nil end - # :inherit: + # Gets the data with the *key*. + # In case the data is missing, returns an exception `DODB::MissingEntry`. # # Data needs to be cloned in case it will be modified, otherwise it will mess with indexes. # # WARNING: data isn't cloned. + # WARNING: may raise a MissingEntry exception. def [](key : Int32) : V @data[key] rescue raise MissingEntry.new(key) end diff --git a/src/dodb/storage/stacked.cr b/src/dodb/storage/stacked.cr index baff129..eb8cfd3 100644 --- a/src/dodb/storage/stacked.cr +++ b/src/dodb/storage/stacked.cr @@ -1,15 +1,53 @@ # Stacked database: only recently requested entries are kept in memory. +# # Most recently used entries are in cache and put on the top of the stack. # Least recently used entries may be removed from the cache in order to keep the amount of memory used reasonable. # +# This database is relevant for high demand applications; +# which means both a high number of entries (data cannot fit entirely in RAM), +# and a high number of requests. +# Typically a retail website. +# In such applications, the "keep the most recently used data in cache" policy works since new users +# constantly push commonly requested data on top of the stack. +# +# ``` +# # Creates a DODB stacked database. +# car_database = DODB::Storage::Stacked.new "/path/to/db" +# +# # Creates a (cached) index. +# cars_by_name = car_database.new_index "name", &.name +# +# # Add a value in the database. +# car_database << Car.new "Corvet" +# ``` +# On the file-system: +# ```plain +# storage +# ├── data +# │   └── 0000000000 +# ├── indices +# │   └── by_name <- the "name" basic index +# │   └── Corvet -> ../../data/0000000000 +# ``` +# # NOTE: fast for frequently requested data and requires a stable (and configurable) amount of memory. # TODO: not yet implemented. class DODB::Storage::Stacked(V) < DODB::Storage::Cached(V) - # The maximum number of accepted entries in the cache. - property max_entries : Int32 + # The *stack* a simple FIFO instance where the key of the requested data is pushed. + # In case the number of stored entries exceeds what is allowed, the least recently used entry is removed. + property stack : FIFO(Int32) # Initializes the `StackedDataBase` with a maximum number of entries in the cache. def initialize(directory_name : String, @max_entries : Int32 = 100_000) super directory_name + @stack = FIFO(Int32).new @max_entries + end + + def [](key : Int32) : V + val = @data[key] rescue raise MissingEntry.new(key) + if entry_to_remove = @stack << key + @data.delete entry_to_remove + end + val end end