more stuff that doesn't work

This commit is contained in:
Andreas Rumpf 2017-05-16 09:56:55 +02:00
commit eb78bc7a51

View file

@ -4,11 +4,26 @@
## Can also use a page manager for allocations. The page manager be used ## Can also use a page manager for allocations. The page manager be used
## to off load pages to a file system or to send it over the wire. ## to off load pages to a file system or to send it over the wire.
## Todo:
## - Add logic to deal with the fact that keys do not have to be unique.
## - Ranged queries
## - Make it generic and low level
## - Support for external nodes and a page cache
const const
M = 4 # max children per B-tree node = M-1 M = 4 # max children per B-tree node = M-1
# (must be even and greater than 2) # (must be even and greater than 2)
Mhalf = M div 2 Mhalf = M div 2
SupportFullTableScan = true
SupportDuplicateKeys = true
## Due to the fact that leaves are shared among multiple BTrees the following
## fields in a Node are downright impossible:
## - parent
## - next
## - prev
type type
Key = string Key = string
Val = string Val = string
@ -24,6 +39,12 @@ type
root: Node root: Node
height: int ## height height: int ## height
n: int ## number of key-value pairs n: int ## number of key-value pairs
CmpKind {.pure.} = enum
eq, le, lt, ge, gt, neq
Cursor = object
n: Node
i, dir: int
up: seq[(Node, int)]
proc newBTree(): BTree = BTree(root: Node(m: 0, isInternal: false)) proc newBTree(): BTree = BTree(root: Node(m: 0, isInternal: false))
@ -42,6 +63,86 @@ proc search(x: Node, key: Key, ht: int): Val =
if j+1 == x.m or less(key, x.keys[j+1]): if j+1 == x.m or less(key, x.keys[j+1]):
return search(x.links[j], key, ht-1) return search(x.links[j], key, ht-1)
proc `=~`(i: int; k: CmpKind): bool =
## check if the result of 'cmp' matches what was requested by 'k':
case k
of CmpKind.eq: i == 0
of CmpKind.le: i <= 0
of CmpKind.lt: i < 0
of CmpKind.ge: i >= 0
of CmpKind.gt: i > 0
of CmpKind.neq: i != 0
proc canPrune(i: int; k: CmpKind): bool =
case k
of CmpKind.eq:
# we demand equality so if bigger, we can prune:
i > 0
of CmpKind.le:
i > 0
of CmpKind.lt: i >= 0
of CmpKind.ge: i < 0
of CmpKind.gt: i <= 0
of CmpKind.neq: i != 0
proc startingPoint(x: Node; key: Key; kind: CmpKind): Cursor =
if x.isInternal:
for j in 0 ..< x.m:
if j+1 == x.m or cmp(key, x.keys[j+1]) =~ kind:
return startingPoint(x.links[j], key, kind)
else:
for j in 0 ..< x.m:
let cmpRes = cmp(key, x.keys[j])
if cmpRes =~ kind: return Cursor(n: x, i: j)
proc dos(x: Node; key: Key; kind: CmpKind; withKey: proc(k: Key; v: Val)) =
if not x.isInternal:
echo "came here"
for j in 0 ..< x.m:
if cmp(key, x.keys[j]) =~ kind:
withKey(x.keys[j+1], x.vals[j])
else:
for j in 0 ..< x.m-1:
let cmpRes = cmp(key, x.keys[j+1])
echo "came here B ", canPrune(cmpRes, kind)
if not canPrune(cmpRes, kind): #cmpRes =~ kind:
dos(x.links[j], key, kind, withKey)
#if canPrune(cmpRes, kind): return
# XXX j+1==x.m case?
proc init(x: Node): Cursor =
result.up = @[]
result.i = 0
var it = x
while it.isInternal:
result.up.add((it, 0))
it = it.links[0]
result.n = it
proc next(c: var Cursor) =
assert c.n != nil
if c.i >= c.n.m:
# current leaf exhausted, pick the next one:
if c.up.len > 0:
(c.n, c.i) = c.up.pop()
inc c.i
var u = 1
while c.i > c.n.m or c.n.isInternal:
if c.up.len > 0:
(c.n, c.i) = c.up[c.up.len - u]
else:
c.n = nil
return
assert(c.n == nil or not c.n.isInternal)
proc atEnd(c: Cursor): bool = c.n == nil
proc getKey(c: Cursor): Key = discard
proc getVal(c: Cursor): Val = discard
proc get(t: BTree; key: Key): Val = search(t.root, key, t.height) proc get(t: BTree; key: Key): Val = search(t.root, key, t.height)
proc copyHalf(h, result: Node; offset: int) = proc copyHalf(h, result: Node; offset: int) =
@ -187,59 +288,61 @@ proc `$`(b: BTree): string =
result = "" result = ""
toString(b.root, b.height, "", result) toString(b.root, b.height, "", result)
proc main = when isMainModule:
var st = newBTree() proc main =
st.put("www.cs.princeton.edu", "abc") var st = newBTree()
st.put("www.cs.princeton.edu", "xyz") st.put("www.cs.princeton.edu", "abc")
st.put("www.princeton.edu", "128.112.128.15") st.put("www.cs.princeton.edu", "xyz")
st.put("www.yale.edu", "130.132.143.21") st.put("www.princeton.edu", "128.112.128.15")
st.put("www.simpsons.com", "209.052.165.60") st.put("www.yale.edu", "130.132.143.21")
st.put("www.apple.com", "17.112.152.32") st.put("www.simpsons.com", "209.052.165.60")
st.put("www.amazon.com", "207.171.182.16") st.put("www.apple.com", "17.112.152.32")
st.put("www.ebay.com", "66.135.192.87") st.put("www.amazon.com", "207.171.182.16")
st.put("www.cnn.com", "64.236.16.20") st.put("www.ebay.com", "66.135.192.87")
st.put("www.google.com", "216.239.41.99") st.put("www.cnn.com", "64.236.16.20")
st.put("www.nytimes.com", "199.239.136.200") st.put("www.google.com", "216.239.41.99")
st.put("www.microsoft.com", "207.126.99.140") st.put("www.nytimes.com", "199.239.136.200")
st.put("www.dell.com", "143.166.224.230") st.put("www.microsoft.com", "207.126.99.140")
st.put("www.slashdot.org", "66.35.250.151") st.put("www.dell.com", "143.166.224.230")
st.put("www.espn.com", "199.181.135.201") st.put("www.slashdot.org", "66.35.250.151")
st.put("www.weather.com", "63.111.66.11") st.put("www.espn.com", "199.181.135.201")
st.put("www.yahoo.com", "216.109.118.65") st.put("www.weather.com", "63.111.66.11")
st.put("www.yahoo.com", "216.109.118.65")
assert st.get("www.cs.princeton.edu") == "abc" assert st.get("www.cs.princeton.edu") == "abc"
assert st.get("www.harvardsucks.com") == nil assert st.get("www.harvardsucks.com") == nil
assert st.get("www.simpsons.com") == "209.052.165.60" assert st.get("www.simpsons.com") == "209.052.165.60"
assert st.get("www.apple.com") == "17.112.152.32" assert st.get("www.apple.com") == "17.112.152.32"
assert st.get("www.ebay.com") == "66.135.192.87" assert st.get("www.ebay.com") == "66.135.192.87"
assert st.get("www.dell.com") == "143.166.224.230" assert st.get("www.dell.com") == "143.166.224.230"
assert(st.n == 17) assert(st.n == 17)
when false: when false:
var b2 = newBTree() var b2 = newBTree()
const iters = 10_000 const iters = 10_000
for i in 1..iters: for i in 1..iters:
b2.put($i, $(iters - i)) b2.put($i, $(iters - i))
for i in 1..iters: for i in 1..iters:
let x = b2.get($i) let x = b2.get($i)
if x != $(iters - i): if x != $(iters - i):
echo "got ", x, ", but expected ", iters - i echo "got ", x, ", but expected ", iters - i
echo b2.n echo b2.n
echo b2.height echo b2.height
when true: when true:
var b1 = newBTree() var b1 = newBTree()
var b2 = newBTree() var b2 = newBTree()
const iters = 60_000 const iters = 10 #60_000
for i in 1..iters: for i in 1..iters:
b2 = b2.putPs($i, $(iters - i)) b2 = b2.putPs($i, $(iters - i))
b1.put($i, $(iters - i)) b1.put($i, $(iters - i))
for i in 1..iters: for i in 1..iters:
let x = b2.get($i) let x = b2.get($i)
if x != $(iters - i): if x != $(iters - i):
echo i, "th iteration; got ", x, ", but expected ", iters - i echo i, "th iteration; got ", x, ", but expected ", iters - i
echo b2.n, " = ", b1.n echo b2.n, " = ", b1.n
echo b2.height, " = ", b1.height echo b2.height, " = ", b1.height
dos(b1.root, "5", CmpKind.eq, proc(k: Key; v: Val) = echo("k ", k, " = ", v))
main() main()