Skip to content
Permalink
Browse files

Merge pull request #97 from gel-rb/previous-multikey

Support both pre- and post-#83 SDBM key formats
  • Loading branch information
matthewd committed Dec 31, 2019
2 parents 450d831 + e98ba05 commit 10c0e057e789bb532c194bdaae37c4ba1ba18aa7
Showing with 56 additions and 9 deletions.
  1. +23 −9 lib/gel/db.rb
  2. +33 −0 test/db_test.rb
@@ -194,11 +194,12 @@ def [](key)

if value =~ /\A~(\d+)\z/
value = $1.to_i.times.map do |idx|
@sdbm["#{key}~#{idx}"]
@sdbm["#{key}~#{idx}"] || @sdbm["#{key}---#{idx}"] ||
raise("missing key: " + "#{key}~#{idx}".inspect)
end.join
end

return Marshal.load(value)
Marshal.load(value)
end


@@ -211,21 +212,34 @@ def [](key)
# amount of extra values stored to hold the split string. This amount is
# determined by string size split by the arbitrary limit imposed by SDBM
def []=(key, value)
return unless value && key
raise if key.nil?

if value.nil?
delete key
return
end

key = key.to_s

dump = Marshal.dump(value)
slicesize = SDBM_PAIRMAX - key.length - 3 # "#{key}~#{i}" where i <= 99
slices = dump.length / slicesize + 1

if (existing_value = @sdbm[key]) && existing_value =~ /\A~(\d+)\z/ && $1.to_i > slices
$1.to_i.times do |idx|
@sdbm.delete("#{key}~#{idx}") || @sdbm.delete("#{key}---#{idx}")
end
end

if slices > 1
slices.times.map do |idx|
slicekey = "#{key.to_s}~#{idx}"
slices.times do |idx|
slicekey = "#{key}~#{idx}"
slicedump = dump.slice!(0, slicesize)
@sdbm[slicekey] = slicedump
end
@sdbm["#{key.to_s}"] = "~#{slices}"
@sdbm[key] = "~#{slices}"
else
@sdbm[key.to_s] = dump
@sdbm[key] = dump
end
end

@@ -235,11 +249,11 @@ def delete(key)

if value =~ /\A~(\d+)\z/
$1.to_i.times.map do |idx|
@sdbm.delete("#{key}~#{idx}")
@sdbm.delete("#{key}~#{idx}") || @sdbm.delete("#{key}---#{idx}")
end.join
end

return Marshal.load(value)
Marshal.load(value)
end
end

@@ -36,4 +36,37 @@ def test_sdbm_store_value_retrieval
assert_equal db['test'], hash_string
end
end

def test_previous_multikey_format
skip unless defined? ::SDBM
Dir.mktmpdir do |dir|
db = Gel::DB::SDBM.new(dir, "test-store")

sdbm = db.instance_variable_get(:@sdbm)
sdbm["test"] = "~4"
sdbm["test---0"] = "\x04\x08\"\x09a"
sdbm["test---1"] = "b"
sdbm["test---2"] = "c"
sdbm["test---3"] = "d"

assert_equal "abcd", db["test"]

assert_equal %w(test test---0 test---1 test---2 test---3), sdbm.keys.sort

db["test"] = "short"

assert_equal %w(test), sdbm.keys.sort

sdbm["test"] = "~4"
sdbm["test---0"] = "\x04\x08\"\x09a"
sdbm["test---1"] = "b"
sdbm["test---2"] = "c"
sdbm["test---3"] = "d"

long_string = "*" * (Gel::DB::SDBM::SDBM_PAIRMAX + 200)
db["test"] = long_string

assert_equal %w(test test~0 test~1), sdbm.keys.sort
end
end
end

0 comments on commit 10c0e05

Please sign in to comment.
You can’t perform that action at this time.