Skip to content

Commit

Permalink
added specs for searchskiplist, implemented search method (without re…
Browse files Browse the repository at this point in the history
…versive thing)
  • Loading branch information
Oleg Andreev committed Apr 27, 2008
1 parent 4cbefc5 commit 9b327d7
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 5 deletions.
69 changes: 68 additions & 1 deletion lib/strokedb/data_structures/search_skiplist.rb
Expand Up @@ -40,6 +40,68 @@ def empty?
!node_next(@head, 0)
end

# Complicated search algorithm.
# Implementation plan:
# 1. no reverse, no with_keys - just find a start_key and move until end_key or limit.
# 2. with_keys support
# 3. reverse support
#
def search(start_key, end_key, limit, offset, reverse, with_keys)
offset ||= 0

start_node = find_by_prefix(start_key, reverse)
!start_node and return []

start_node = skip_nodes(start_node, offset, reverse)
!start_node and return []

collect_values(start_node, end_key, limit, reverse, with_keys)
end

#
#
def find_by_prefix(start_key, reverse)
# TODO: add reverse support
!start_key and return node_next(node_first, 0)
x = find_nearest_node(start_key)
start_key and node_key(x)[0, start_key.size] != start_key and return nil
x
end

#
#
def skip_nodes(node, offset, reverse)
# TODO: add reverse support
tail = @tail
while offset > 0 && node != tail
node = node_next(x, 0)
offset -= 1
end
offset == 0 ? node : nil
end

#
#
def collect_values(x, end_prefix, limit, reverse, with_keys)
# TODO: add reverse support
values = []
meth = method(with_keys ? :node_pair : :node_value)
tail = @tail
limit ||= Float::MAX
while x != tail
if end_prefix
node_compare(x, end_prefix) > 0 and return values
end
values.size >= limit and return values
values << meth.call(x).freeze
x = node_next(x, 0)
end
values
end




# First key of a non-empty skiplist (nil for empty one)
#
def first_key
Expand Down Expand Up @@ -90,6 +152,7 @@ def find_with_update(x, level, key, update) #:nodoc:
# Find is thread-safe and requires no mutexes locking.
def find_nearest_node(key) #:nodoc:
x = node_first
!key and return x
level = node_level(x)
while level > 0
level -= 1
Expand Down Expand Up @@ -168,7 +231,7 @@ def find_nearest_node(key) #:nodoc:
def find_nearest(key)
node_value(find_nearest_node(key))
end

# Returns value, associated with key. nil if key is not found.
#
def find(key)
Expand Down Expand Up @@ -282,6 +345,10 @@ def node_compare(x, key)
x[1] <=> key
end

def node_pair(x)
x[1,2]
end

def node_key(x)
x[1]
end
Expand Down
2 changes: 1 addition & 1 deletion lib/strokedb/views/view.rb
Expand Up @@ -13,7 +13,7 @@ module StrokeDB
# or to <tt>false</tt> if the size is not fixed.
# Note: optimized storage is used when both keys and values are the fixed length.
# I.e. both "value_size" and "key_size" are set.
"value_size" => StrokeDB::Util::RAW_UUID_SIZE,
"value_size" => Util::RAW_UUID_SIZE,

# strategy determines whether to index HEADs or particular versions
# When :heads is used, previous versions are removed from the index.
Expand Down
10 changes: 7 additions & 3 deletions lib/strokedb/views/view_storage.rb
Expand Up @@ -5,6 +5,9 @@ class ViewStorage
def initialize(options = {})
# TODO: find out whether the view indexfile exists and read
# its options

@skiplist = SearchSkiplist.new

end

def set_options(options)
Expand All @@ -16,10 +19,11 @@ def set_options(options)

end

#
#
#
def find(start_key, end_key, key, limit, offset, reverse, with_keys)

def find(start_key, end_key, limit, offset, reverse, with_keys)
# how smart...
@skiplist.search(start_key, end_key, limit, offset, reverse, with_keys)
end

#
Expand Down
22 changes: 22 additions & 0 deletions spec/lib/strokedb/data_structures/search_skiplist_spec.rb
Expand Up @@ -192,6 +192,28 @@
@list.find_nearest("g").should == "F"
end
end

describe "SearchSkiplist#search" do
before(:each) do
@list = SearchSkiplist.new
@keys = %w[ a aa ab b ba bb x xx xy xyz ]
@values = @keys.map{|v| v + " value"}
@key_values = @keys.map{|v| [v, v + " value"]}
@key_values.each do |k, v|
@list.insert(k, v)
end
end

it "should find all items" do
@list.search(nil, nil, nil, nil, nil, nil).should == @values
end

it "should find all items with keys" do
@list.search(nil, nil, nil, nil, nil, true).should == @key_values
end

end

end

def raw_list(list)
Expand Down

0 comments on commit 9b327d7

Please sign in to comment.