Some tests and extra code for parallelization of DODB.

remotes/1708105384931250775/master
Luka Vandervelden 2020-07-20 14:23:10 +02:00
parent 9990a3ac1b
commit 2dd42f3a30
2 changed files with 84 additions and 6 deletions

View File

@ -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

View File

@ -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. Well 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)