From 800d139a3db273bf9b2a4d6562c9c6dfc012975b Mon Sep 17 00:00:00 2001 From: Luka Vandervelden Date: Wed, 24 Jun 2020 21:45:45 +0200 Subject: [PATCH] WIP for lock files and atomic operations. --- spec/test.cr | 22 ++++++++++++++++++++++ src/dodb.cr | 25 +++++++++++++++++++++++++ src/dodb/index.cr | 15 +++++++++++++++ src/dodb/lib_c.cr | 9 +++++++++ 4 files changed, 71 insertions(+) create mode 100644 src/dodb/lib_c.cr diff --git a/spec/test.cr b/spec/test.cr index ac4204f..43863d1 100644 --- a/spec/test.cr +++ b/spec/test.cr @@ -396,6 +396,28 @@ describe "DODB::DataBase" do end end + describe "atomic operations" do + it "safe_get and safe_get?" do + db = DODB::SpecDataBase.new + + db_ships_by_name = db.new_index "name", &.name + + Ship.all_ships.each do |ship| + db << ship + end + + Ship.all_ships.each do |ship| + db_ships_by_name.safe_get ship.name do |results| + results.should eq(ship) + end + + db_ships_by_name.safe_get? ship.name do |results| + results.should eq(ship) + end + end + end + end + describe "tools" do it "rebuilds indexes" do db = DODB::SpecDataBase.new diff --git a/src/dodb.cr b/src/dodb.cr index 28fad7d..2a34db6 100644 --- a/src/dodb.cr +++ b/src/dodb.cr @@ -8,6 +8,7 @@ class DODB::DataBase(V) def initialize(@directory_name : String) Dir.mkdir_p data_path + Dir.mkdir_p locks_directory begin self.last_index @@ -43,6 +44,22 @@ class DODB::DataBase(V) end end + def request_lock(name) + r = -1 + file_path = get_lock_file_path name + file_perms = 0o644 + + flags = LibC::O_EXCL | LibC::O_CREAT + while (r = LibC.open file_path, flags, file_perms) == -1 + sleep 1.milliseconds + end + + LibC.close r + end + def release_lock(name) + File.delete get_lock_file_path name + end + ## # name is the name that will be used on the file system. def new_partition(name : String, &block : Proc(V, String)) @@ -279,6 +296,14 @@ class DODB::DataBase(V) "#{data_path}/%010i.json" % key end + private def locks_directory : String + "#{@directory_name}/locks" + end + + private def get_lock_file_path(name : String) + "#{locks_directory}/#{name}.lock" + end + private def read(file_path : String) V.from_json ::File.read file_path end diff --git a/src/dodb/index.cr b/src/dodb/index.cr index df79068..5c518f3 100644 --- a/src/dodb/index.cr +++ b/src/dodb/index.cr @@ -68,6 +68,21 @@ class DODB::Index(V) < DODB::Indexer(V) nil end + def safe_get(index : String) : Nil + internal_key = get_key(index).to_s + @storage.request_lock internal_key + + yield get index + + @storage.release_lock internal_key + end + + def safe_get?(index : String, &block : Proc(V | Nil, Nil)) : Nil + safe_get index, &block + rescue MissingEntry + yield nil + end + def get_key(index : String) : Int32 file_path = file_path_index index diff --git a/src/dodb/lib_c.cr b/src/dodb/lib_c.cr new file mode 100644 index 0000000..5a32b78 --- /dev/null +++ b/src/dodb/lib_c.cr @@ -0,0 +1,9 @@ + +lib LibC + {% if flag?(:linux) %} + O_EXCL = 0o200 + {% elsif flag?(:openbsd) %} + O_EXCL = 0x0800 + {% end %} +end +