func (dl directoryLayer) Exists(rt fdb.ReadTransactor, path []string) (bool, error) { r, e := rt.ReadTransact(func(rtr fdb.ReadTransaction) (interface{}, error) { if e := dl.checkVersion(rtr, nil); e != nil { return false, e } node := dl.find(rtr, path).prefetchMetadata(rtr) if !node.exists() { return false, nil } if node.isInPartition(nil, false) { nc, e := node.getContents(dl, nil) if e != nil { return false, e } return nc.Exists(rtr, node.getPartitionSubpath()) } return true, nil }) if e != nil { return false, e } return r.(bool), nil }
func (dl directoryLayer) List(rt fdb.ReadTransactor, path []string) ([]string, error) { r, e := rt.ReadTransact(func(rtr fdb.ReadTransaction) (interface{}, error) { if e := dl.checkVersion(rtr, nil); e != nil { return nil, e } node := dl.find(rtr, path).prefetchMetadata(rtr) if !node.exists() { return nil, errors.New("the directory does not exist") } if node.isInPartition(nil, true) { nc, e := node.getContents(dl, nil) if e != nil { return nil, e } return nc.List(rtr, node.getPartitionSubpath()) } return dl.subdirNames(rtr, node.subspace) }) if e != nil { return nil, e } return r.([]string), nil }
func (dl directoryLayer) Open(rt fdb.ReadTransactor, path []string, layer []byte) (DirectorySubspace, error) { r, e := rt.ReadTransact(func(rtr fdb.ReadTransaction) (interface{}, error) { return dl.createOrOpen(rtr, nil, path, layer, nil, false, true) }) if e != nil { return nil, e } return r.(DirectorySubspace), nil }
func (sm *StackMachine) processInst(idx int, inst tuple.Tuple) { defer func() { if r := recover(); r != nil { switch r := r.(type) { case fdb.Error: sm.store(idx, []byte(tuple.Tuple{[]byte("ERROR"), []byte(fmt.Sprintf("%d", r.Code))}.Pack())) default: panic(r) } } }() var e error op := inst[0].(string) if sm.verbose { fmt.Printf("%d. Instruction is %s (%v)\n", idx, op, sm.prefix) fmt.Printf("Stack from [") sm.dumpStack() fmt.Printf(" ]\n") } var t fdb.Transactor var rt fdb.ReadTransactor var isDB bool switch { case strings.HasSuffix(op, "_SNAPSHOT"): rt = sm.tr.Snapshot() op = op[:len(op)-9] case strings.HasSuffix(op, "_DATABASE"): t = db rt = db op = op[:len(op)-9] isDB = true default: t = sm.tr rt = sm.tr } switch { case op == "PUSH": sm.store(idx, inst[1]) case op == "DUP": entry := sm.stack[len(sm.stack)-1] sm.store(entry.idx, entry.item) case op == "EMPTY_STACK": sm.stack = []stackEntry{} sm.stack = make([]stackEntry, 0) case op == "SWAP": idx := sm.waitAndPop().item.(int64) sm.stack[len(sm.stack)-1], sm.stack[len(sm.stack)-1-int(idx)] = sm.stack[len(sm.stack)-1-int(idx)], sm.stack[len(sm.stack)-1] case op == "POP": sm.stack = sm.stack[:len(sm.stack)-1] case op == "SUB": sm.store(idx, sm.waitAndPop().item.(int64)-sm.waitAndPop().item.(int64)) case op == "NEW_TRANSACTION": sm.tr, e = db.CreateTransaction() if e != nil { panic(e) } case op == "ON_ERROR": sm.store(idx, sm.tr.OnError(fdb.Error{int(sm.waitAndPop().item.(int64))})) case op == "GET_READ_VERSION": _, e = rt.ReadTransact(func(rtr fdb.ReadTransaction) (interface{}, error) { sm.lastVersion = rtr.GetReadVersion().MustGet() sm.store(idx, []byte("GOT_READ_VERSION")) return nil, nil }) if e != nil { panic(e) } case op == "SET": sm.executeMutation(t, func(tr fdb.Transaction) (interface{}, error) { tr.Set(fdb.Key(sm.waitAndPop().item.([]byte)), sm.waitAndPop().item.([]byte)) return nil, nil }, isDB, idx) case op == "LOG_STACK": prefix := sm.waitAndPop().item.([]byte) for i := len(sm.stack) - 1; i >= 0; i-- { if i%100 == 0 { sm.tr.Commit().MustGet() } el := sm.waitAndPop() var keyt tuple.Tuple keyt = append(keyt, int64(i)) keyt = append(keyt, int64(el.idx)) pk := append(prefix, keyt.Pack()...) var valt tuple.Tuple valt = append(valt, el.item) pv := valt.Pack() vl := 40000 if len(pv) < vl { vl = len(pv) } sm.tr.Set(fdb.Key(pk), pv[:vl]) } sm.tr.Commit().MustGet() case op == "GET": _, e = rt.ReadTransact(func(rtr fdb.ReadTransaction) (interface{}, error) { sm.store(idx, rtr.Get(fdb.Key(sm.waitAndPop().item.([]byte)))) return nil, nil }) if e != nil { panic(e) } case op == "COMMIT": sm.store(idx, sm.tr.Commit()) case op == "RESET": sm.tr.Reset() case op == "CLEAR": sm.executeMutation(t, func(tr fdb.Transaction) (interface{}, error) { tr.Clear(fdb.Key(sm.waitAndPop().item.([]byte))) return nil, nil }, isDB, idx) case op == "SET_READ_VERSION": sm.tr.SetReadVersion(sm.lastVersion) case op == "WAIT_FUTURE": entry := sm.waitAndPop() sm.store(entry.idx, entry.item) case op == "GET_COMMITTED_VERSION": sm.lastVersion, e = sm.tr.GetCommittedVersion() if e != nil { panic(e) } sm.store(idx, []byte("GOT_COMMITTED_VERSION")) case op == "GET_KEY": sel := sm.popSelector() _, e = rt.ReadTransact(func(rtr fdb.ReadTransaction) (interface{}, error) { sm.store(idx, rtr.GetKey(sel)) return nil, nil }) if e != nil { panic(e) } case strings.HasPrefix(op, "GET_RANGE"): var r fdb.Range switch op[9:] { case "_STARTS_WITH": r = sm.popPrefixRange() case "_SELECTOR": r = fdb.SelectorRange{sm.popSelector(), sm.popSelector()} case "": r = sm.popKeyRange() } ro := sm.popRangeOptions() _, e = rt.ReadTransact(func(rtr fdb.ReadTransaction) (interface{}, error) { sm.pushRange(idx, rtr.GetRange(r, ro).GetSliceOrPanic()) return nil, nil }) if e != nil { panic(e) } case strings.HasPrefix(op, "CLEAR_RANGE"): var er fdb.ExactRange switch op[11:] { case "_STARTS_WITH": er = sm.popPrefixRange() case "": er = sm.popKeyRange() } sm.executeMutation(t, func(tr fdb.Transaction) (interface{}, error) { tr.ClearRange(er) return nil, nil }, isDB, idx) case op == "TUPLE_PACK": var t tuple.Tuple count := sm.waitAndPop().item.(int64) for i := 0; i < int(count); i++ { t = append(t, sm.waitAndPop().item) } sm.store(idx, []byte(t.Pack())) case op == "TUPLE_UNPACK": t, e := tuple.Unpack(fdb.Key(sm.waitAndPop().item.([]byte))) if e != nil { panic(e) } for _, el := range t { sm.store(idx, []byte(tuple.Tuple{el}.Pack())) } case op == "TUPLE_RANGE": var t tuple.Tuple count := sm.waitAndPop().item.(int64) for i := 0; i < int(count); i++ { t = append(t, sm.waitAndPop().item) } bk, ek := t.FDBRangeKeys() sm.store(idx, []byte(bk.FDBKey())) sm.store(idx, []byte(ek.FDBKey())) case op == "START_THREAD": newsm := newStackMachine(sm.waitAndPop().item.([]byte), verbose, sm.de) sm.threads.Add(1) go func() { newsm.Run() sm.threads.Done() }() case op == "WAIT_EMPTY": prefix := sm.waitAndPop().item.([]byte) er, e := fdb.PrefixRange(prefix) if e != nil { panic(e) } db.Transact(func(tr fdb.Transaction) (interface{}, error) { v := tr.GetRange(er, fdb.RangeOptions{}).GetSliceOrPanic() if len(v) != 0 { panic(fdb.Error{1020}) } return nil, nil }) sm.store(idx, []byte("WAITED_FOR_EMPTY")) case op == "READ_CONFLICT_RANGE": e = sm.tr.AddReadConflictRange(fdb.KeyRange{fdb.Key(sm.waitAndPop().item.([]byte)), fdb.Key(sm.waitAndPop().item.([]byte))}) if e != nil { panic(e) } sm.store(idx, []byte("SET_CONFLICT_RANGE")) case op == "WRITE_CONFLICT_RANGE": e = sm.tr.AddWriteConflictRange(fdb.KeyRange{fdb.Key(sm.waitAndPop().item.([]byte)), fdb.Key(sm.waitAndPop().item.([]byte))}) if e != nil { panic(e) } sm.store(idx, []byte("SET_CONFLICT_RANGE")) case op == "READ_CONFLICT_KEY": e = sm.tr.AddReadConflictKey(fdb.Key(sm.waitAndPop().item.([]byte))) if e != nil { panic(e) } sm.store(idx, []byte("SET_CONFLICT_KEY")) case op == "WRITE_CONFLICT_KEY": e = sm.tr.AddWriteConflictKey(fdb.Key(sm.waitAndPop().item.([]byte))) if e != nil { panic(e) } sm.store(idx, []byte("SET_CONFLICT_KEY")) case op == "ATOMIC_OP": opname := strings.Replace(strings.Title(strings.Replace(strings.ToLower(sm.waitAndPop().item.(string)), "_", " ", -1)), " ", "", -1) key := fdb.Key(sm.waitAndPop().item.([]byte)) value := sm.waitAndPop().item.([]byte) sm.executeMutation(t, func(tr fdb.Transaction) (interface{}, error) { reflect.ValueOf(tr).MethodByName(opname).Call([]reflect.Value{reflect.ValueOf(key), reflect.ValueOf(value)}) return nil, nil }, isDB, idx) case op == "DISABLE_WRITE_CONFLICT": sm.tr.Options().SetNextWriteNoWriteConflictRange() case op == "CANCEL": sm.tr.Cancel() case op == "UNIT_TESTS": db.Options().SetLocationCacheSize(100001) db.Options().SetMaxWatches(10001) tr, e := db.CreateTransaction() if e != nil { panic(e) } tr.Options().SetPrioritySystemImmediate() tr.Options().SetPriorityBatch() tr.Options().SetCausalReadRisky() tr.Options().SetCausalWriteRisky() tr.Options().SetReadYourWritesDisable() tr.Options().SetReadAheadDisable() tr.Options().SetReadSystemKeys() tr.Options().SetAccessSystemKeys() tr.Options().SetDurabilityDevNullIsWebScale() tr.Options().SetTimeout(1000) tr.Options().SetRetryLimit(5) tr.Options().SetMaxRetryDelay(100) tr.Get(fdb.Key("\xff")).MustGet() tr.Commit().MustGet() sm.testWatches() sm.testLocality() case strings.HasPrefix(op, "DIRECTORY_"): sm.de.processOp(sm, op[10:], isDB, idx, t, rt) default: log.Fatalf("Unhandled operation %s\n", string(inst[0].([]byte))) } if sm.verbose { fmt.Printf(" to [") sm.dumpStack() fmt.Printf(" ]\n\n") } runtime.Gosched() }