Beispiel #1
0
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
}
Beispiel #2
0
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
}
Beispiel #3
0
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
}
Beispiel #4
0
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()
}