예제 #1
0
func (dl directoryLayer) contentsOfNode(node subspace.Subspace, path []string, layer []byte) (DirectorySubspace, error) {
	p, e := dl.nodeSS.Unpack(node)
	if e != nil {
		return nil, e
	}
	prefix := p[0]

	newPath := make([]string, len(dl.path)+len(path))
	copy(newPath, dl.path)
	copy(newPath[len(dl.path):], path)

	pb := prefix.([]byte)
	ss := subspace.FromBytes(pb)

	if bytes.Compare(layer, []byte("partition")) == 0 {
		nssb := make([]byte, len(pb)+1)
		copy(nssb, pb)
		nssb[len(pb)] = 0xFE
		ndl := NewDirectoryLayer(subspace.FromBytes(nssb), ss, false).(directoryLayer)
		ndl.path = newPath
		return directoryPartition{ndl, dl}, nil
	} else {
		return directorySubspace{ss, dl, newPath, layer}, nil
	}
}
예제 #2
0
// NewDirectoryLayer returns a new root directory (as a Directory). The
// subspaces nodeSS and contentSS control where the directory metadata and
// contents are stored. The default root directory has a nodeSS of
// subspace.FromBytes([]byte{0xFE}) and a contentSS of
// subspace.AllKeys(). Specifying more restrictive values for nodeSS and
// contentSS will allow using the directory layer alongside other content in a
// database.
//
// If allowManualPrefixes is false, all calls to CreatePrefix on the returned
// Directory (or any subdirectories) will fail, and all directory prefixes will
// be automatically allocated. The default root directory does not allow manual
// prefixes.
func NewDirectoryLayer(nodeSS, contentSS subspace.Subspace, allowManualPrefixes bool) Directory {
	var dl directoryLayer

	dl.nodeSS = subspace.FromBytes(nodeSS.Bytes())
	dl.contentSS = subspace.FromBytes(contentSS.Bytes())

	dl.allowManualPrefixes = allowManualPrefixes

	dl.rootNode = dl.nodeSS.Sub(dl.nodeSS.Bytes())
	dl.allocator = newHCA(dl.rootNode.Sub([]byte("hca")))

	return dl
}
예제 #3
0
		}
	}
	return true
}

func moveTo(t fdb.Transactor, dl directoryLayer, path, newAbsolutePath []string) (DirectorySubspace, error) {
	partition_len := len(dl.path)

	if !stringsEqual(newAbsolutePath[:partition_len], dl.path) {
		return nil, errors.New("cannot move between partitions")
	}

	return dl.Move(t, path[partition_len:], newAbsolutePath[partition_len:])
}

var root = NewDirectoryLayer(subspace.FromBytes([]byte{0xFE}), subspace.AllKeys(), false)

// CreateOrOpen opens the directory specified by path (resolved relative to the
// default root directory), and returns the directory and its contents as a
// DirectorySubspace. If the directory does not exist, it is created (creating
// parent directories if necessary).
//
// If the byte slice layer is specified and the directory is new, it is recorded
// as the layer; if layer is specified and the directory already exists, it is
// compared against the layer specified when the directory was created, and an
// error is returned if they differ.
func CreateOrOpen(t fdb.Transactor, path []string, layer []byte) (DirectorySubspace, error) {
	return root.CreateOrOpen(t, path, layer)
}

// Open opens the directory specified by path (resolved relative to the default
예제 #4
0
func (de *DirectoryExtension) processOp(sm *StackMachine, op string, isDB bool, idx int, t fdb.Transactor, rt fdb.ReadTransactor) {
	defer func() {
		if r := recover(); r != nil {
			sm.store(idx, []byte("DIRECTORY_ERROR"))
			if createOps[op] {
				de.store(nil)
			}
		}
	}()

	var e error

	switch {
	case op == "CREATE_SUBSPACE":
		tuples := sm.popTuples(1)
		rp := sm.waitAndPop().item.([]byte)
		s := subspace.FromBytes(rp).Sub(tuples[0]...)
		de.store(s)
	case op == "CREATE_LAYER":
		idx1 := sm.waitAndPop().item.(int64)
		idx2 := sm.waitAndPop().item.(int64)
		amp := sm.waitAndPop().item.(int64)
		nodeSS := de.list[idx1]
		contentSS := de.list[idx2]

		if nodeSS == nil || contentSS == nil {
			de.store(nil)
		} else {
			de.store(directory.NewDirectoryLayer(nodeSS.(subspace.Subspace), contentSS.(subspace.Subspace), (amp == int64(1))))
		}
	case op == "CREATE_OR_OPEN":
		tuples := sm.popTuples(1)
		l := sm.waitAndPop().item
		var layer []byte
		if l != nil {
			layer = l.([]byte)
		}
		d, e := de.cwd().CreateOrOpen(t, tupleToPath(tuples[0]), layer)
		if e != nil {
			panic(e)
		}
		de.store(d)
	case op == "CREATE":
		tuples := sm.popTuples(1)
		l := sm.waitAndPop().item
		var layer []byte
		if l != nil {
			layer = l.([]byte)
		}
		p := sm.waitAndPop().item
		var d directory.Directory
		if p == nil {
			d, e = de.cwd().Create(t, tupleToPath(tuples[0]), layer)
		} else {
			// p.([]byte) itself may be nil, but CreatePrefix handles that appropriately
			d, e = de.cwd().CreatePrefix(t, tupleToPath(tuples[0]), layer, p.([]byte))
		}
		if e != nil {
			panic(e)
		}
		de.store(d)
	case op == "OPEN":
		tuples := sm.popTuples(1)
		l := sm.waitAndPop().item
		var layer []byte
		if l != nil {
			layer = l.([]byte)
		}
		d, e := de.cwd().Open(rt, tupleToPath(tuples[0]), layer)
		if e != nil {
			panic(e)
		}
		de.store(d)
	case op == "CHANGE":
		i := sm.waitAndPop().item.(int64)
		if de.list[i] == nil {
			i = de.errorIndex
		}
		de.index = i
	case op == "SET_ERROR_INDEX":
		de.errorIndex = sm.waitAndPop().item.(int64)
	case op == "MOVE":
		tuples := sm.popTuples(2)
		d, e := de.cwd().Move(t, tupleToPath(tuples[0]), tupleToPath(tuples[1]))
		if e != nil {
			panic(e)
		}
		de.store(d)
	case op == "MOVE_TO":
		tuples := sm.popTuples(1)
		d, e := de.cwd().MoveTo(t, tupleToPath(tuples[0]))
		if e != nil {
			panic(e)
		}
		de.store(d)
	case strings.HasPrefix(op, "REMOVE"):
		path := sm.maybePath()
		// This ***HAS*** to call Transact to ensure that any directory version
		// key set in the process of trying to remove this potentially
		// non-existent directory, in the REMOVE but not REMOVE_IF_EXISTS case,
		// doesn't end up committing the version key. (Other languages have
		// separate remove() and remove_if_exists() so don't have this tricky
		// issue).
		_, e := t.Transact(func(tr fdb.Transaction) (interface{}, error) {
			ok, e := de.cwd().Remove(tr, path)
			if e != nil {
				panic(e)
			}
			switch op[6:] {
			case "":
				if !ok {
					panic("directory does not exist")
				}
			case "_IF_EXISTS":
			}
			return nil, nil
		})
		if e != nil {
			panic(e)
		}
	case op == "LIST":
		subs, e := de.cwd().List(rt, sm.maybePath())
		if e != nil {
			panic(e)
		}
		t := make(tuple.Tuple, len(subs))
		for i, s := range subs {
			t[i] = s
		}
		sm.store(idx, t.Pack())
	case op == "EXISTS":
		b, e := de.cwd().Exists(rt, sm.maybePath())
		if e != nil {
			panic(e)
		}
		if b {
			sm.store(idx, int64(1))
		} else {
			sm.store(idx, int64(0))
		}
	case op == "PACK_KEY":
		tuples := sm.popTuples(1)
		sm.store(idx, de.css().Pack(tuples[0]))
	case op == "UNPACK_KEY":
		t, e := de.css().Unpack(fdb.Key(sm.waitAndPop().item.([]byte)))
		if e != nil {
			panic(e)
		}
		for _, el := range t {
			sm.store(idx, el)
		}
	case op == "RANGE":
		ss := de.css().Sub(sm.popTuples(1)[0]...)
		bk, ek := ss.FDBRangeKeys()
		sm.store(idx, bk)
		sm.store(idx, ek)
	case op == "CONTAINS":
		k := sm.waitAndPop().item.([]byte)
		b := de.css().Contains(fdb.Key(k))
		if b {
			sm.store(idx, int64(1))
		} else {
			sm.store(idx, int64(0))
		}
	case op == "OPEN_SUBSPACE":
		de.store(de.css().Sub(sm.popTuples(1)[0]...))
	case op == "LOG_SUBSPACE":
		k := sm.waitAndPop().item.([]byte)
		k = append(k, tuple.Tuple{de.index}.Pack()...)
		v := de.css().Bytes()
		t.Transact(func(tr fdb.Transaction) (interface{}, error) {
			tr.Set(fdb.Key(k), v)
			return nil, nil
		})
	case op == "LOG_DIRECTORY":
		rp := sm.waitAndPop().item.([]byte)
		ss := subspace.FromBytes(rp).Sub(de.index)
		k1 := ss.Pack(tuple.Tuple{"path"})
		v1 := tuplePackStrings(de.cwd().GetPath())
		k2 := ss.Pack(tuple.Tuple{"layer"})
		v2 := tuple.Tuple{de.cwd().GetLayer()}.Pack()
		k3 := ss.Pack(tuple.Tuple{"exists"})
		var v3 []byte
		exists, e := de.cwd().Exists(rt, nil)
		if e != nil {
			panic(e)
		}
		if exists {
			v3 = tuple.Tuple{1}.Pack()
		} else {
			v3 = tuple.Tuple{0}.Pack()
		}
		k4 := ss.Pack(tuple.Tuple{"children"})
		var subs []string
		if exists {
			subs, e = de.cwd().List(rt, nil)
			if e != nil {
				panic(e)
			}
		}
		v4 := tuplePackStrings(subs)
		t.Transact(func(tr fdb.Transaction) (interface{}, error) {
			tr.Set(k1, v1)
			tr.Set(k2, v2)
			tr.Set(k3, v3)
			tr.Set(k4, v4)
			return nil, nil
		})
	case op == "STRIP_PREFIX":
		ba := sm.waitAndPop().item.([]byte)
		ssb := de.css().Bytes()
		if !bytes.HasPrefix(ba, ssb) {
			panic("prefix mismatch")
		}
		ba = ba[len(ssb):]
		sm.store(idx, ba)
	}
}