Commit 9eca74ec authored by Kirill Smelkov's avatar Kirill Smelkov

X Teach AllStructs to emit topologies with values

parent 3568e415
...@@ -532,13 +532,14 @@ def Restructure(ztree, newStructure): ...@@ -532,13 +532,14 @@ def Restructure(ztree, newStructure):
# specified keys and btree depth up-to maxdepth. Each tree node is split by # specified keys and btree depth up-to maxdepth. Each tree node is split by
# up-to maxsplit points. # up-to maxsplit points.
# #
# Generated trees contains key-only Buckets. # kv is {} that defines values to be linked from buckets.
# By default kv=None and generated trees contains key-only Buckets.
# #
# If allowEmptyBuckets=y tree structures with empty buckets are also generated. # If allowEmptyBuckets=y tree structures with empty buckets are also generated.
# By default, except for empty-tree case, only tree structures with non-empty # By default, except for empty-tree case, only tree structures with non-empty
# buckets are generated, because ZODB BTree package misbehaves if it finds an # buckets are generated, because ZODB BTree package misbehaves if it finds an
# empty bucket in a trees. ZODB.BTree._check also asserts if bucket is empty. # empty bucket in a trees. ZODB.BTree._check also asserts if bucket is empty.
def AllStructs(keys, maxdepth, maxsplit, allowEmptyBuckets=False): # -> i[] of Tree def AllStructs(keys, maxdepth, maxsplit, allowEmptyBuckets=False, kv=None): # -> i[] of Tree
assert isinstance(maxdepth, int); assert maxdepth >= 0 assert isinstance(maxdepth, int); assert maxdepth >= 0
assert isinstance(maxsplit, int); assert maxsplit >= 0 assert isinstance(maxsplit, int); assert maxsplit >= 0
ks = set(keys) ks = set(keys)
...@@ -556,18 +557,18 @@ def AllStructs(keys, maxdepth, maxsplit, allowEmptyBuckets=False): # -> i[] of T ...@@ -556,18 +557,18 @@ def AllStructs(keys, maxdepth, maxsplit, allowEmptyBuckets=False): # -> i[] of T
else: else:
# the only possible case for empty tree is T/B # the only possible case for empty tree is T/B
if not allowEmptyBuckets: if not allowEmptyBuckets:
yield Tree([], Bucket([], None)) yield Tree([], Bucket([], None if kv is None else []))
return return
# XXX ok? (ideally should be -inf,+inf) # XXX ok? (ideally should be -inf,+inf)
klo = 0 klo = 0
khi = 0 khi = 0
for tree in _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets): for tree in _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets, kv):
yield tree yield tree
def _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets): def _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets, kv):
assert klo <= khi assert klo <= khi
_assertIncv(keyv) _assertIncv(keyv)
if len(keyv) > 0: if len(keyv) > 0:
...@@ -593,7 +594,10 @@ def _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets): ...@@ -593,7 +594,10 @@ def _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets):
bkeyv = _keyvSliceBy(keyv, xlo, xhi) bkeyv = _keyvSliceBy(keyv, xlo, xhi)
if not allowEmptyBuckets: if not allowEmptyBuckets:
assert len(bkeyv) > 0 assert len(bkeyv) > 0
children.append(Bucket(bkeyv, None)) valuev = None
if kv is not None:
valuev = [kv[k] for k in bkeyv]
children.append(Bucket(bkeyv, valuev))
else: else:
yield Tree(ksplitv[1:-1], *children) # (s1, s2, ..., sN) yield Tree(ksplitv[1:-1], *children) # (s1, s2, ..., sN)
...@@ -606,7 +610,7 @@ def _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets): ...@@ -606,7 +610,7 @@ def _allStructs(klo, khi, keyv, maxdepth, maxsplit, allowEmptyBuckets):
if not allowEmptyBuckets: if not allowEmptyBuckets:
assert len(ckeyv) > 0 assert len(ckeyv) > 0
ichildrenv.append( _allStructs( ichildrenv.append( _allStructs(
xlo, xhi, ckeyv, maxdepth - 1, maxsplit, allowEmptyBuckets)) xlo, xhi, ckeyv, maxdepth - 1, maxsplit, allowEmptyBuckets, kv))
else: else:
for children in itertools.product(*ichildrenv): for children in itertools.product(*ichildrenv):
yield Tree(ksplitv[1:-1], *children) # (s1, s2, ..., sN) yield Tree(ksplitv[1:-1], *children) # (s1, s2, ..., sN)
......
...@@ -124,13 +124,13 @@ def test_allStructs(): ...@@ -124,13 +124,13 @@ def test_allStructs():
# X = AllStructs(..., allowEmptyBuckets=True) # X = AllStructs(..., allowEmptyBuckets=True)
# Y = AllStructs(..., allowEmptyBuckets=False) # Y = AllStructs(..., allowEmptyBuckets=False)
# XY = X = Y + assert X == Y # XY = X = Y + assert X == Y
def X(keys, maxdepth, maxsplit, allowEmptyBuckets=True): def X(keys, maxdepth, maxsplit, allowEmptyBuckets=True, kv=None):
return list(xbtree.AllStructs(keys, maxdepth, maxsplit, allowEmptyBuckets)) return list(xbtree.AllStructs(keys, maxdepth, maxsplit, allowEmptyBuckets, kv))
def Y(keys, maxdepth, maxsplit): def Y(keys, maxdepth, maxsplit, kv=None):
return X(keys, maxdepth, maxsplit, allowEmptyBuckets=False) return X(keys, maxdepth, maxsplit, allowEmptyBuckets=False, kv=kv)
def XY(keys, maxdepth, maxsplit): def XY(keys, maxdepth, maxsplit, kv=None):
x = X(keys, maxdepth, maxsplit) x = X(keys, maxdepth, maxsplit, kv=kv)
y = Y(keys, maxdepth, maxsplit) y = Y(keys, maxdepth, maxsplit, kv=kv)
assert x == y assert x == y
return x return x
...@@ -355,9 +355,9 @@ def test_allStructs(): ...@@ -355,9 +355,9 @@ def test_allStructs():
# TODO test for maxsplit=2 / maxdepth=2 vvv # TODO test for maxsplit=2 / maxdepth=2 vvv
def TY(keys, maxdepth, maxsplit): def TY(keys, maxdepth, maxsplit, kv=None):
yv = Y(keys, maxdepth, maxsplit) yv = Y(keys, maxdepth, maxsplit, kv=kv)
return list([xbtree.TopoEncode(_) for _ in yv]) return list([xbtree.TopoEncode(_, vencode=lambda v: v) for _ in yv])
assert TY([1,3], 1, 1) == [ assert TY([1,3], 1, 1) == [
'T/B1,3', 'T/B1,3',
...@@ -370,6 +370,18 @@ def test_allStructs(): ...@@ -370,6 +370,18 @@ def test_allStructs():
'T3/T-T/B1-B3', 'T3/T-T/B1-B3',
] ]
# with values
assert TY([1,3], 1,1, kv={1:'a',3:'c'}) == [
'T/B1:a,3:c',
'T/T/B1:a,3:c',
'T/T2/B1:a-B3:c',
'T/T3/B1:a-B3:c',
'T2/B1:a-B3:c',
'T2/T-T/B1:a-B3:c',
'T3/B1:a-B3:c',
'T3/T-T/B1:a-B3:c',
]
# XBlk simulates ZBlk without xbtree_test.py depending on file_zodb.py # XBlk simulates ZBlk without xbtree_test.py depending on file_zodb.py
class XBlk(Persistent): class XBlk(Persistent):
......
...@@ -79,6 +79,7 @@ from golang import func, defer, panic ...@@ -79,6 +79,7 @@ from golang import func, defer, panic
from golang import time from golang import time
from ZODB import DB from ZODB import DB
from ZODB.Connection import Connection from ZODB.Connection import Connection
from ZODB.MappingStorage import MappingStorage
import transaction import transaction
import random import random
...@@ -190,12 +191,10 @@ def Trees(zstor, r): ...@@ -190,12 +191,10 @@ def Trees(zstor, r):
xbtree.Restructure(ztree, tree) xbtree.Restructure(ztree, tree)
head = commit("treegen/trees: %s" % treetxt) head = commit("treegen/trees: %s" % treetxt)
# XXX print more details?
# XXX print just tid (as `zodb commit` does) ?
#xprint("txn %s -> tree(%s) %s" % (ashex(tid), ashex(ztree._p_oid), treetxt))
xprint("%s" % ashex(head)) xprint("%s" % ashex(head))
"""
# AllStructs generates subset of all possible tree changes in # AllStructs generates subset of all possible tree changes in
# between kv1 and kv2. See top-level documentation for details. # between kv1 and kv2. See top-level documentation for details.
@func @func
...@@ -270,6 +269,62 @@ def AllStructs(zstor, kv1txt, kv2txt, n, seed=None): ...@@ -270,6 +269,62 @@ def AllStructs(zstor, kv1txt, kv2txt, n, seed=None):
assert tstruct in t2structv assert tstruct in t2structv
emit(delta, verify, tstruct) emit(delta, verify, tstruct)
"""
# AllStructs generates topologies for subset of all possible tree changes in
# between kv1 and kv2. See top-level documentation for details.
@func
def AllStructs(kv1txt, kv2txt, n, seed=None):
zstor = MappingStorage() # in RAM storage to ... XXX writy why we need it
zctx = ZCtx(zstor)
defer(zctx.close)
kv1 = kvDecode(kv1txt, zctx.vdecode)
kv2 = kvDecode(kv2txt, zctx.vdecode)
print("# allstructs %s %s" % (kv1txt, kv2txt))
#print("# n=%d kv1=%s kv2=%s" % (n, kv1txt, kv2txt))
# create the tree
ztree = zctx.root['ztree'] = XLOTree()
commit('init')
# initial kv1 and kv2 states with topologies prepared as ZODB would do natively
patch(ztree, diff({}, kv1), verify=kv1)
commit('kv1')
t1struct0 = xbtree.StructureOf(ztree)
patch(ztree, diff(kv1, kv2), verify=kv2)
commit('kv2')
t2struct0 = xbtree.StructureOf(ztree)
# all tree topologies that can represent kv1 and kv2
maxdepth=2 # XXX -> 3?
maxsplit=1 # XXX -> 2?
t1AllStructs = list(xbtree.AllStructs(kv1.keys(), maxdepth, maxsplit, kv=kv1))
t2AllStructs = list(xbtree.AllStructs(kv2.keys(), maxdepth, maxsplit, kv=kv2))
# seed
if seed is None:
seed = int(time.now())
random.seed(seed)
print("# n=%d seed=%d" % (n, seed))
# all tree1 and tree2 topologies jumps in between we are going to emit:
# native + n random ones.
t1structv = [t1struct0] + random.sample(t1AllStructs, min(n, len(t1AllStructs)))
t2structv = [t2struct0] + random.sample(t2AllStructs, min(n, len(t2AllStructs)))
# emit topologies for tree1->tree2 and tree1<-tree2 transitions for all
# combinations of tree1 and tree2.
t12travel = list(bitravel2Way(t1structv, t2structv))
for i,tstruct in enumerate(t12travel):
if i%2 == 0:
assert tstruct in t1structv
else:
assert tstruct in t2structv
print(zctx.TopoEncode(tstruct))
# bitravel2Way generates travel path through all A<->B edges such # bitravel2Way generates travel path through all A<->B edges such
...@@ -391,18 +446,13 @@ def TopoDecode(zctx, text): ...@@ -391,18 +446,13 @@ def TopoDecode(zctx, text):
@func @func
def cmd_allstructs(argv): def cmd_allstructs(argv):
if len(argv) != 4: if len(argv) != 3:
print("Usage: treegen allstructs <zurl> <n> <kv1> <kv2>", file=sys.stderr) print("Usage: treegen allstructs <n> <kv1> <kv2>", file=sys.stderr)
sys.exit(1) sys.exit(1)
zurl = argv[0] n = int(argv[0])
n = int(argv[1]) kv1, kv2 = argv[1:]
kv1, kv2 = argv[2:] AllStructs(kv1, kv2, n)
zstor = storageFromURL(zurl)
defer(zstor.close)
AllStructs(zstor, kv1, kv2, n)
@func @func
def cmd_trees(argv): def cmd_trees(argv):
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment