From 7584c3acc0391b69806f219b3e50a2caa526ea3d Mon Sep 17 00:00:00 2001 From: Karchnu Date: Fri, 26 Apr 2024 19:35:00 +0200 Subject: [PATCH] Rewrite of the tag mechanism. Tests are needed. --- spec/test.cr | 2 +- src/dodb/tags.cr | 116 ++++++++++++++++++++++++----------------------- 2 files changed, 61 insertions(+), 57 deletions(-) diff --git a/spec/test.cr b/spec/test.cr index 456da00..13e0685 100644 --- a/spec/test.cr +++ b/spec/test.cr @@ -277,7 +277,7 @@ describe "DODB::DataBase" do end # Removing the “flagship” tag, brace for impact. - flagship, index = db_ships_by_tags.get_with_indices("flagship")[0] + flagship, index = db_ships_by_tags.get_with_indice("flagship")[0] flagship.tags = [] of String db[index] = flagship diff --git a/src/dodb/tags.cr b/src/dodb/tags.cr index f7b0e85..1e269fc 100644 --- a/src/dodb/tags.cr +++ b/src/dodb/tags.cr @@ -10,48 +10,27 @@ class DODB::Tags(V) < DODB::Indexer(V) ::Dir.mkdir_p indexing_directory end - # FIXME: The slow is damn too high. - def tag_combinations(tags) - combinations = [] of Array(String) - - tags.size.times do |i| - combinations.concat tags.permutations (i+1) - end - - return combinations + def check!(key, value, old_value) + return true # Tags don’t have collisions or overloads. end def index(key, value) - indices = key_proc.call(value).sort - - tag_combinations(indices).each do |previous_indices| - # FIXME: Not on `index`, but on the list of all previous indices. - symdir = symlinks_directory previous_indices - otdir = other_tags_directory previous_indices - - ::Dir.mkdir_p symdir - ::Dir.mkdir_p otdir - - symlink = get_tagged_entry_path(key, previous_indices) + indices = key_proc.call(value) + indices.each do |i| + symlink = get_tagged_entry_path(i, key) + Dir.mkdir_p ::File.dirname symlink + # FIXME: Should not happen anymore. Should we remove this? ::File.delete symlink if ::File.exists? symlink - - ::File.symlink get_data_symlink(key, previous_indices), symlink + ::File.symlink get_data_symlink(key), symlink end end def deindex(key, value) - indices = key_proc.call(value).sort + indices = key_proc.call(value) - tag_combinations(indices).each do |previous_indices| - # FIXME: Not on `index`, but on the list of all previous indices. - symdir = symlinks_directory previous_indices - otdir = other_tags_directory previous_indices - - ::Dir.mkdir_p symdir - ::Dir.mkdir_p otdir - - symlink = get_tagged_entry_path(key, previous_indices) + indices.each do |i| + symlink = get_tagged_entry_path(i, key) ::File.delete symlink if ::File.exists? symlink @@ -59,24 +38,16 @@ class DODB::Tags(V) < DODB::Indexer(V) end end - def check!(key, value, old_value) - return true # Tags don’t have collisions or overloads. - end - - def get_with_indices(key : String) : Array(Tuple(V, Int32)) - get_with_indices [key] - end - - def get_with_indices(keys : Array(String)) : Array(Tuple(V, Int32)) + def get_with_indice(tag : String) : Array(Tuple(V, Int32)) r_value = Array(Tuple(V, Int32)).new - partition_directory = symlinks_directory keys + tag_directory = indexing_directory tag - return r_value unless Dir.exists? partition_directory + return r_value unless Dir.exists? tag_directory - Dir.each_child partition_directory do |child| + Dir.each_child tag_directory do |child| r_value << { - V.from_json(::File.read("#{partition_directory}/#{child}")), + V.from_json(::File.read("#{tag_directory}/#{child}")), File.basename(child).gsub(/\.json$/, "").to_i } end @@ -84,30 +55,63 @@ class DODB::Tags(V) < DODB::Indexer(V) r_value end - def get(key : String) : Array(V) - get_with_indices(key).map &.[0] + def get_with_indices(keys : Array(String)) : Array(Tuple(V, Int32)) + r_value = Array(Tuple(V, Int32)).new + keys.each do |tag| + r_value.concat get_with_indice tag + end + r_value + end + + def get(tag : String) : Array(V) + get_with_indice(tag).map &.[0] end def get(keys : Array(String)) : Array(V) get_with_indices(keys.sort).map &.[0] end + def delete(tag) + delete tag, do true end + end + + def delete(tag, &matcher) + tag_directory = indexing_directory tag + + return unless Dir.exists? tag_directory + + Dir.each_child tag_directory do |child| + path = "#{tag_directory}/#{child}" + item = V.from_json ::File.read path + + if yield item + key = get_key path + @storage.delete key + end + end + end + + private def get_key(path : String) : Int32 + ::File.readlink(path) + .sub(/\.json$/, "") + .sub(/^.*\//, "") + .to_i + end + def indexing_directory : String "#{@storage_root}/tags/by_#{@name}" end - private def symlinks_directory(previous_indices : Array(String)) - "#{indexing_directory}#{previous_indices.map { |i| "/other-tags/#{i}" }.join}/data" - end - private def other_tags_directory(previous_indices : Array(String)) - "#{indexing_directory}#{previous_indices.map { |i| "/other-tags/#{i}" }.join}/other-tags" + private def indexing_directory(tag) + "#{indexing_directory}/#{tag}" end - private def get_tagged_entry_path(key : String, indices : Array(String)) - "#{indexing_directory}#{indices.map { |i| "/other-tags/#{i}" }.join}/data/#{key}.json" + private def get_tagged_entry_path(tag : String, key : String) + "#{indexing_directory}/#{tag}/#{key}.json" end - private def get_data_symlink(key : String, indices : Array(String)) - "../../../#{indices.map { "../../" }.join}/data/#{key}.json" + + private def get_data_symlink(key : String) + "../../../data/#{key}.json" end end