From 2dd42f3a3085d9c346668b956cd6c2c3e7f00874 Mon Sep 17 00:00:00 2001 From: Luka Vandervelden Date: Mon, 20 Jul 2020 14:23:10 +0200 Subject: [PATCH] Some tests and extra code for parallelization of DODB. --- spec/test.cr | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dodb.cr | 26 ++++++++++++++++----- 2 files changed, 84 insertions(+), 6 deletions(-) diff --git a/spec/test.cr b/spec/test.cr index 43863d1..31c5778 100644 --- a/spec/test.cr +++ b/spec/test.cr @@ -482,5 +482,69 @@ describe "DODB::DataBase" do end end end + + describe "parallel support" do + # Not sure how many forks would be safe in a test like that. + fork_count = 25 + entries_per_fork = 100 + + it "works for pushing values" do + db = DODB::SpecDataBase.new + + processes = [] of Process + + fork_count.times do |fork_id| + processes << Process.fork do + entries_per_fork.times do |entry_id| + db << Ship.new("entry-#{fork_id}-#{entry_id}", "???") + end + end + end + + processes.each &.wait + + dump = db.to_a + + dump.size.should eq fork_count * entries_per_fork + end + + it "works for updating values" do + db = DODB::SpecDataBase.new + db_entries_by_name = db.new_index "name", &.name + + # First pass, creating data. + processes = [] of Process + fork_count.times do |fork_id| + processes << Process.fork do + entries_per_fork.times do |entry_id| + db << Ship.new("entry-#{fork_id}-#{entry_id}", "???") + end + end + end + processes.each &.wait + + # Second pass, updating data. + processes = [] of Process + fork_count.times do |fork_id| + processes << Process.fork do + entries_per_fork.times do |entry_id| + db_entries_by_name.update Ship.new("entry-#{fork_id}-#{entry_id}", "???", tags: ["updated"]) + end + end + end + processes.each &.wait + + # Third pass, testing database content. + dump = db.to_a + + fork_count.times do |fork_id| + entries_per_fork.times do |entry_id| + entry = db_entries_by_name.get "entry-#{fork_id}-#{entry_id}" + + entry.tags.should eq ["updated"] + end + end + end + end end diff --git a/src/dodb.cr b/src/dodb.cr index 72dabe4..e5f1411 100644 --- a/src/dodb.cr +++ b/src/dodb.cr @@ -44,9 +44,9 @@ class DODB::DataBase(V) end end - def request_lock(name) + def request_lock(name, subname = nil) r = -1 - file_path = get_lock_file_path name + file_path = get_lock_file_path name, subname file_perms = 0o644 flags = LibC::O_EXCL | LibC::O_CREAT @@ -56,8 +56,8 @@ class DODB::DataBase(V) LibC.close r end - def release_lock(name) - File.delete get_lock_file_path name + def release_lock(name, subname = nil) + File.delete get_lock_file_path name, subname end ## @@ -107,11 +107,17 @@ class DODB::DataBase(V) end def <<(item : V) + request_lock "index" + index = last_index + 1 self[index] = item self.last_index = index + + release_lock "index" + + index # FIXME: Should we really return the internal key? end def []?(key : Int32) : V? @@ -160,6 +166,8 @@ class DODB::DataBase(V) end def pop + request_lock "index" + index = last_index # Some entries may have been removed. We’ll skip over those. @@ -178,6 +186,8 @@ class DODB::DataBase(V) last_index = index - 1 + release_lock "index" + poped end @@ -306,8 +316,12 @@ class DODB::DataBase(V) "#{@directory_name}/locks" end - private def get_lock_file_path(name : String) - "#{locks_directory}/#{name}.lock" + private def get_lock_file_path(name : String, subname : String? = nil) + if subname + "#{locks_directory}/#{name}-#{subname}.lock" # FIXME: Separator that causes less collisions? + else + "#{locks_directory}/#{name}.lock" + end end private def read(file_path : String)