Compare commits

...

2 Commits

Author SHA1 Message Date
f29fbfb850 Common 2024-05-28 03:29:01 +02:00
c105b7fa33 Fix Common implementation. 2024-05-28 03:28:40 +02:00
3 changed files with 52 additions and 27 deletions

View File

@ -197,7 +197,7 @@ end
Let's create a DODB database for our cars. Let's create a DODB database for our cars.
.SOURCE Ruby ps=9 vs=10 .SOURCE Ruby ps=9 vs=10
# Database creation # Database creation
database = DODB::Storage::Basic(Car).new "path/to/db-cars" database = DODB::Storage::Uncached(Car).new "path/to/db-cars"
# Adding an element to the db # Adding an element to the db
database << Car.new "Corvet", "red", ["elegant", "fast"] database << Car.new "Corvet", "red", ["elegant", "fast"]
@ -485,7 +485,7 @@ A cached database has the same API as the other DODB databases and keeps a copy
database = DODB::Storage::Cached(Car).new "path/to/db-cars" database = DODB::Storage::Cached(Car).new "path/to/db-cars"
.SOURCE .SOURCE
All operations of the All operations of the
.CLASS Storage::Basic .CLASS Storage::Uncached
class are available for class are available for
.CLASS Storage::Cached . .CLASS Storage::Cached .
.QE .QE
@ -532,7 +532,7 @@ along with its related data from the cache.
.B "Implementation details" . .B "Implementation details" .
The implementation is time-efficient; The implementation is time-efficient;
the duration of adding a value is constant, it doesn't change with the number of entries. the duration of adding a value is almost constant, it doesn't change much with the number of entries.
This efficiency is a memory tradeoff. This efficiency is a memory tradeoff.
All the entries are added to a All the entries are added to a
.B "double-linked list" .B "double-linked list"
@ -549,6 +549,15 @@ Moreover,
.I "common database" .I "common database"
enables to adjust the number of stored entries. enables to adjust the number of stored entries.
. .
.QP
.SOURCE Ruby ps=9 vs=10
# Create a database with a data cache limited to 100.000 entries
database = DODB::Storage::Common(Car).new "path/to/db-cars", 100000
.SOURCE
The
.CLASS Storage::Common
class has the same API as the other database classes.
.QE
. .
.SECTION RAM-only database for short-lived data .SECTION RAM-only database for short-lived data
Databases are built around the objective to actually Databases are built around the objective to actually
@ -610,23 +619,26 @@ This way, one can opt for a cached index and, after some time not using the file
. .
. .
.SECTION DODB and memory constraint .SECTION DODB and memory constraint
In contrast with the previous section, some environments have a memory constraint. Some environments may have very peculiar constraints, where caching data would cause problems or would be inefficient anyway\*[*].
For example, in case the database is larger than the available memory, it won't be possible to use a data cache\*[*].
.FOOTNOTE1 .FOOTNOTE1
Keep in mind that for the moment "cached database" means "all data in memory". Caching would be inefficient for databases where the distribution of requests is homogeneous between the different entries, for example.
It is perfectly reasonable to have a cached database with a policy of keeping just a certain amount of values in memory, in order to limit the memory required by selecting the relevant values to keep in cache (the most recently used, for example). If the requests are random, without a small portion of the data receiving most requests (such as a Pareto distribution), caching becomes mostly irrelevant.
But for now, the cached version keeps everything.
See the "Future work" section.
.FOOTNOTE2 .FOOTNOTE2
In these cases, the
.B "Uncached database" .
The
.CLASS "DODB::Storage::Uncached" .CLASS "DODB::Storage::Uncached"
database has no data cache at all and can be used in very constrained environments. can be used\*[*].
.FOOTNOTE1
However, the However, the
.CLASS DODB::Storage::Common .CLASS DODB::Storage::Common
should (probably) be considered instead, even if the configured number of entries is low. should be considered instead for most applications, even if the configured number of entries is low due to low RAM.
A small data cache is still better than no cache. .FOOTNOTE2
.
.QP
.SOURCE Ruby ps=9 vs=10
# Uncached database creation
database = DODB::Storage::Uncached(Car).new "path/to/db-cars"
.SOURCE
.QE
.B "Uncached indexes" . .B "Uncached indexes" .
Cached indexes do not require a large amount of memory since the only stored data is an integer (the Cached indexes do not require a large amount of memory since the only stored data is an integer (the
@ -664,10 +676,11 @@ command enables to browse the full documentation with a web browser.
.SS Database creation .SS Database creation
.QP .QP
.SOURCE Ruby ps=9 vs=10 .SOURCE Ruby ps=9 vs=10
# Uncached, cached and RAM-only database creation. # Uncached, cached, common and RAM-only database creation.
database = DODB::Storage::Basic(Car).new "path/to/db-cars" database = DODB::Storage::Uncached(Car).new "path/to/db"
database = DODB::Storage::Cached(Car).new "path/to/db-cars" database = DODB::Storage::Cached(Car).new "path/to/db"
database = DODB::Storage::RAMOnly(Car).new "path/to/db-cars" database = DODB::Storage::Common(Car).new "path/to/db", 50000 # nb cache entries
database = DODB::Storage::RAMOnly(Car).new "path/to/db"
.SOURCE .SOURCE
.QE .QE
. .
@ -712,7 +725,7 @@ function.
.KE .KE
. .
. .
.SS Triggers creation .SS Trigger creation
.QP .QP
.SOURCE Ruby ps=9 vs=10 .SOURCE Ruby ps=9 vs=10
# Uncached, cached and RAM-only basic indexes. # Uncached, cached and RAM-only basic indexes.

View File

@ -171,16 +171,19 @@ def bench_50_shades_of_fifo()
cars_fifo1 = SPECDB::Common(Car).new "-1k", 1_000 cars_fifo1 = SPECDB::Common(Car).new "-1k", 1_000
cars_fifo5 = SPECDB::Common(Car).new "-5k", 5_000 cars_fifo5 = SPECDB::Common(Car).new "-5k", 5_000
cars_fifo10 = SPECDB::Common(Car).new "-10k", 10_000 cars_fifo10 = SPECDB::Common(Car).new "-10k", 10_000
cars_fifo20 = SPECDB::Common(Car).new "-20k", 20_000
fifo_Sby_name1, fifo_Sby_color1, fifo_Sby_keywords1 = cached_indexes cars_fifo1 fifo_Sby_name1, fifo_Sby_color1, fifo_Sby_keywords1 = cached_indexes cars_fifo1
fifo_Sby_name5, fifo_Sby_color5, fifo_Sby_keywords5 = cached_indexes cars_fifo5 fifo_Sby_name5, fifo_Sby_color5, fifo_Sby_keywords5 = cached_indexes cars_fifo5
fifo_Sby_name10, fifo_Sby_color10, fifo_Sby_keywords10 = cached_indexes cars_fifo10 fifo_Sby_name10, fifo_Sby_color10, fifo_Sby_keywords10 = cached_indexes cars_fifo10
fifo_Sby_name20, fifo_Sby_color20, fifo_Sby_keywords20 = cached_indexes cars_fifo20
fn = ->search_benchmark(DODB::Storage(Car), Int32, String, DODB::Trigger::Index(Car), DODB::Trigger::Partition(Car), DODB::Trigger::Tags(Car)) fn = ->search_benchmark(DODB::Storage(Car), Int32, String, DODB::Trigger::Index(Car), DODB::Trigger::Partition(Car), DODB::Trigger::Tags(Car))
prepare_env cars_fifo1, "fifo1", fifo_Sby_name1, fifo_Sby_color1, fifo_Sby_keywords1, &fn prepare_env cars_fifo1, "fifo1", fifo_Sby_name1, fifo_Sby_color1, fifo_Sby_keywords1, &fn
prepare_env cars_fifo5, "fifo5", fifo_Sby_name5, fifo_Sby_color5, fifo_Sby_keywords5, &fn prepare_env cars_fifo5, "fifo5", fifo_Sby_name5, fifo_Sby_color5, fifo_Sby_keywords5, &fn
prepare_env cars_fifo10, "fifo10", fifo_Sby_name10, fifo_Sby_color10, fifo_Sby_keywords10, &fn prepare_env cars_fifo10, "fifo10", fifo_Sby_name10, fifo_Sby_color10, fifo_Sby_keywords10, &fn
prepare_env cars_fifo20, "fifo20", fifo_Sby_name20, fifo_Sby_color20, fifo_Sby_keywords20, &fn
end end
ENV["REPORT_DIR"]?.try { |report_dir| Context.report_dir = report_dir } ENV["REPORT_DIR"]?.try { |report_dir| Context.report_dir = report_dir }
@ -193,11 +196,13 @@ ENV["DBSIZE_START"]?.try { |it| Context.from = it.to_i }
ENV["DBSIZE_INCREMENT"]?.try { |it| Context.incr = it.to_i } ENV["DBSIZE_INCREMENT"]?.try { |it| Context.incr = it.to_i }
ENV["FIFO_SIZE"]?.try { |it| Context.fifo_size = it.to_u32 } ENV["FIFO_SIZE"]?.try { |it| Context.fifo_size = it.to_u32 }
pp! Context.nb_run puts "REPORT_DIR: #{Context.report_dir}"
pp! Context.from puts "MAXINDEXES: #{Context.max_indexes}"
pp! Context.to puts "NBRUN: #{Context.nb_run}"
pp! Context.incr puts "DBSIZE: #{Context.to}"
pp! Context.max_indexes puts "DBSIZE_START: #{Context.from}"
puts "DBSIZE_INCREMENT: #{Context.incr}"
puts "FIFO_SIZE: #{Context.fifo_size}"
if ARGV.size == 0 if ARGV.size == 0
puts "Usage: benchmark-cars (fifo|search|add)" puts "Usage: benchmark-cars (fifo|search|add)"

View File

@ -33,7 +33,7 @@
# #
# 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.
class DODB::Storage::Common(V) < DODB::Storage::Cached(V) class DODB::Storage::Common(V) < DODB::Storage::Cached(V)
# The *fifo* an `EfficientFIFO` instance where the key of the requested data is pushed. # The *fifo* is an instance of `EfficientFIFO` 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. # In case the number of stored entries exceeds what is allowed, the least recently used entry is removed.
property fifo : EfficientFIFO(Int32) property fifo : EfficientFIFO(Int32)
@ -50,8 +50,15 @@ class DODB::Storage::Common(V) < DODB::Storage::Cached(V)
end end
end end
# Verifies that the value is in cache, or read it on disk.
# Pushes the key in the fifo.
def [](key : Int32) : V def [](key : Int32) : V
val = @data[key] rescue raise MissingEntry.new(key) val = @data[key]?
if val.nil?
raise MissingEntry.new(key) unless ::File.exists? file_path key
val = read file_path key
@data[key] = val
end
push_fifo key push_fifo key
val val
end end