Compare commits
No commits in common. "b38e3f31ba4c77cf9cff642feb2f72021f65881f" and "375f3bdf697f8a36bf31bd1fa535c7788809608e" have entirely different histories.
b38e3f31ba
...
375f3bdf69
@ -1,5 +1,4 @@
|
|||||||
require "file_utils"
|
require "file_utils"
|
||||||
require "json"
|
require "json"
|
||||||
|
|
||||||
require "./fifo.cr" # FIFO class to implement a cache policy.
|
|
||||||
require "./dodb/*" # Databases and indexes (basic indexes, partitions, tags, etc.).
|
require "./dodb/*" # Databases and indexes (basic indexes, partitions, tags, etc.).
|
||||||
|
@ -57,18 +57,19 @@ class DODB::Storage::Cached(V) < DODB::Storage(V)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets data from the hash in RAM.
|
# Getting data from the hash in RAM.
|
||||||
def []?(key : Int32) : V?
|
def []?(key : Int32) : V?
|
||||||
self[key] rescue nil
|
@data[key]
|
||||||
|
rescue e
|
||||||
|
# FIXME: rescues any error the same way.
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
# Gets the data with the *key*.
|
# :inherit:
|
||||||
# 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.
|
# Data needs to be cloned in case it will be modified, otherwise it will mess with indexes.
|
||||||
#
|
#
|
||||||
# WARNING: data isn't cloned.
|
# WARNING: data isn't cloned.
|
||||||
# WARNING: may raise a MissingEntry exception.
|
|
||||||
def [](key : Int32) : V
|
def [](key : Int32) : V
|
||||||
@data[key] rescue raise MissingEntry.new(key)
|
@data[key] rescue raise MissingEntry.new(key)
|
||||||
end
|
end
|
||||||
|
@ -1,53 +1,15 @@
|
|||||||
# Stacked database: only recently requested entries are kept in memory.
|
# 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.
|
# 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.
|
# 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.
|
# NOTE: fast for frequently requested data and requires a stable (and configurable) amount of memory.
|
||||||
# TODO: not yet implemented.
|
# TODO: not yet implemented.
|
||||||
class DODB::Storage::Stacked(V) < DODB::Storage::Cached(V)
|
class DODB::Storage::Stacked(V) < DODB::Storage::Cached(V)
|
||||||
# The *stack* a simple FIFO instance where the key of the requested data is pushed.
|
# The maximum number of accepted entries in the cache.
|
||||||
# In case the number of stored entries exceeds what is allowed, the least recently used entry is removed.
|
property max_entries : Int32
|
||||||
property stack : FIFO(Int32)
|
|
||||||
|
|
||||||
# Initializes the `StackedDataBase` with a maximum number of entries in the cache.
|
# Initializes the `StackedDataBase` with a maximum number of entries in the cache.
|
||||||
def initialize(directory_name : String, @max_entries : Int32 = 100_000)
|
def initialize(directory_name : String, @max_entries : Int32 = 100_000)
|
||||||
super directory_name
|
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
|
||||||
end
|
end
|
||||||
|
37
src/fifo.cr
37
src/fifo.cr
@ -1,37 +0,0 @@
|
|||||||
# This class enables to keep track of used data.
|
|
||||||
#
|
|
||||||
# Each time a value is pushed, it is put on top of a FIFO stack.
|
|
||||||
# Stack size is configurable, so in case the stack size exceeds what is allowed,
|
|
||||||
# the least recently used value is removed.
|
|
||||||
#
|
|
||||||
# ```
|
|
||||||
# fifo = FIFO(Int32).new 3 # Only 3 allowed entries.
|
|
||||||
#
|
|
||||||
# pp! fifo << 1 # -> nil (there is still room in the stack)
|
|
||||||
# pp! fifo << 2 # -> nil (there is still room in the stack)
|
|
||||||
# pp! fifo << 3 # -> nil (last entry without exceeding the allowed size)
|
|
||||||
# pp! fifo << 4 # -> 1 (least recently used data)
|
|
||||||
# pp! fifo << 4 # -> nil (already in the stack)
|
|
||||||
# pp! fifo << 2 # -> nil (already in the stack)
|
|
||||||
# pp! fifo << 5 # -> 3 (least recently used data)
|
|
||||||
# ```
|
|
||||||
class FIFO(V)
|
|
||||||
# This array is used as a *stack*.
|
|
||||||
property data : Array(V)
|
|
||||||
|
|
||||||
# Maximum allowed entries in the stack.
|
|
||||||
property max_entries : UInt32
|
|
||||||
|
|
||||||
def initialize(@max_entries : UInt32)
|
|
||||||
@data = Array(V).new
|
|
||||||
end
|
|
||||||
|
|
||||||
# Pushes a value in the FIFO and gets the oldest value whether it exceeds the allowed number of entries.
|
|
||||||
# NOTE: `#<<(v : V)` is the only function since it's enough for the intended use, feel free to improve this.
|
|
||||||
# WARNING: implementation is extremely simple (3 lines) and not designed to be highly efficient.
|
|
||||||
def <<(v : V) : V?
|
|
||||||
@data.unshift v # push on top of the stack
|
|
||||||
@data.uniq! # remove dups
|
|
||||||
@data.pop if @data.size > @max_entries # remove least recently used entry if `@data` is too big
|
|
||||||
end
|
|
||||||
end
|
|
Loading…
Reference in New Issue
Block a user