Ejemplo n.º 1
0
func (dl directoryLayer) checkVersion(rtr fdb.ReadTransaction, tr *fdb.Transaction) error {
	version := rtr.Get(dl.rootNode.Sub([]byte("version"))).MustGet()

	if version == nil {
		if tr != nil {
			dl.initializeDirectory(*tr)
		}
		return nil
	}

	var versions []int32
	buf := bytes.NewBuffer(version)

	for i := 0; i < 3; i++ {
		var v int32
		err := binary.Read(buf, binary.LittleEndian, &v)
		if err != nil {
			return errors.New("cannot determine directory version present in database")
		}
		versions = append(versions, v)
	}

	if versions[0] > _MAJORVERSION {
		return fmt.Errorf("cannot load directory with version %d.%d.%d using directory layer %d.%d.%d", versions[0], versions[1], versions[2], _MAJORVERSION, _MINORVERSION, _MICROVERSION)
	}

	if versions[1] > _MINORVERSION && tr != nil /* aka write access allowed */ {
		return fmt.Errorf("directory with version %d.%d.%d is read-only when opened using directory layer %d.%d.%d", versions[0], versions[1], versions[2], _MAJORVERSION, _MINORVERSION, _MICROVERSION)
	}

	return nil
}
Ejemplo n.º 2
0
func (n *node) layer(rtr fdb.ReadTransaction) fdb.FutureByteSlice {
	if n._layer == nil {
		fv := rtr.Get(n.subspace.Sub([]byte("layer")))
		n._layer = fv
	}

	return n._layer
}
Ejemplo n.º 3
0
func (dl directoryLayer) find(rtr fdb.ReadTransaction, path []string) *node {
	n := &node{dl.rootNode, []string{}, path, nil}
	for i := range path {
		n = &node{dl.nodeWithPrefix(rtr.Get(n.subspace.Sub(_SUBDIRS, path[i])).MustGet()), path[:i+1], path, nil}
		if !n.exists() || bytes.Compare(n.layer(rtr).MustGet(), []byte("partition")) == 0 {
			return n
		}
	}
	return n
}
Ejemplo n.º 4
0
func (dl directoryLayer) subdirNames(rtr fdb.ReadTransaction, node subspace.Subspace) ([]string, error) {
	sd := node.Sub(_SUBDIRS)

	rr := rtr.GetRange(sd, fdb.RangeOptions{})
	ri := rr.Iterator()

	var ret []string

	for ri.Advance() {
		kv := ri.MustGet()

		p, e := sd.Unpack(kv.Key)
		if e != nil {
			return nil, e
		}

		ret = append(ret, p[0].(string))
	}

	return ret, nil
}
Ejemplo n.º 5
0
func (dl directoryLayer) nodeContainingKey(rtr fdb.ReadTransaction, key []byte) (subspace.Subspace, error) {
	if bytes.HasPrefix(key, dl.nodeSS.Bytes()) {
		return dl.rootNode, nil
	}

	bk, _ := dl.nodeSS.FDBRangeKeys()
	kr := fdb.KeyRange{bk, fdb.Key(append(dl.nodeSS.Pack(tuple.Tuple{key}), 0x00))}

	kvs := rtr.GetRange(kr, fdb.RangeOptions{Reverse: true, Limit: 1}).GetSliceOrPanic()
	if len(kvs) == 1 {
		pp, e := dl.nodeSS.Unpack(kvs[0].Key)
		if e != nil {
			return nil, e
		}
		prevPrefix := pp[0].([]byte)
		if bytes.HasPrefix(key, prevPrefix) {
			return dl.nodeWithPrefix(prevPrefix), nil
		}
	}

	return nil, nil
}
Ejemplo n.º 6
0
func (dl directoryLayer) createOrOpen(rtr fdb.ReadTransaction, tr *fdb.Transaction, path []string, layer []byte, prefix []byte, allowCreate, allowOpen bool) (DirectorySubspace, error) {
	if e := dl.checkVersion(rtr, nil); e != nil {
		return nil, e
	}

	if prefix != nil && !dl.allowManualPrefixes {
		if len(dl.path) == 0 {
			return nil, errors.New("cannot specify a prefix unless manual prefixes are enabled")
		} else {
			return nil, errors.New("cannot specify a prefix in a partition")
		}
	}

	if len(path) == 0 {
		return nil, errors.New("the root directory cannot be opened")
	}

	existingNode := dl.find(rtr, path).prefetchMetadata(rtr)
	if existingNode.exists() {
		if existingNode.isInPartition(nil, false) {
			subpath := existingNode.getPartitionSubpath()
			enc, e := existingNode.getContents(dl, nil)
			if e != nil {
				return nil, e
			}
			return enc.(directoryPartition).createOrOpen(rtr, tr, subpath, layer, prefix, allowCreate, allowOpen)
		}

		if !allowOpen {
			return nil, errors.New("the directory already exists")
		}

		if layer != nil && bytes.Compare(existingNode._layer.MustGet(), layer) != 0 {
			return nil, errors.New("the directory was created with an incompatible layer")
		}

		return existingNode.getContents(dl, nil)
	}

	if !allowCreate {
		return nil, errors.New("the directory does not exist")
	}

	if e := dl.checkVersion(rtr, tr); e != nil {
		return nil, e
	}

	if prefix == nil {
		newss, e := dl.allocator.allocate(*tr, dl.contentSS)
		if e != nil {
			return nil, fmt.Errorf("unable to allocate new directory prefix (%s)", e.Error())
		}

		if !isRangeEmpty(rtr, newss) {
			return nil, fmt.Errorf("the database has keys stored at the prefix chosen by the automatic prefix allocator: %v", prefix)
		}

		prefix = newss.Bytes()

		pf, e := dl.isPrefixFree(rtr.Snapshot(), prefix)
		if e != nil {
			return nil, e
		}
		if !pf {
			return nil, errors.New("the directory layer has manually allocated prefixes that conflict with the automatic prefix allocator")
		}
	} else {
		pf, e := dl.isPrefixFree(rtr, prefix)
		if e != nil {
			return nil, e
		}
		if !pf {
			return nil, errors.New("the given prefix is already in use")
		}
	}

	var parentNode subspace.Subspace

	if len(path) > 1 {
		pd, e := dl.createOrOpen(rtr, tr, path[:len(path)-1], nil, nil, true, true)
		if e != nil {
			return nil, e
		}
		parentNode = dl.nodeWithPrefix(pd.Bytes())
	} else {
		parentNode = dl.rootNode
	}

	if parentNode == nil {
		return nil, errors.New("the parent directory does not exist")
	}

	node := dl.nodeWithPrefix(prefix)
	tr.Set(parentNode.Sub(_SUBDIRS, path[len(path)-1]), prefix)

	if layer == nil {
		layer = []byte{}
	}

	tr.Set(node.Sub([]byte("layer")), layer)

	return dl.contentsOfNode(node, path, layer)
}
Ejemplo n.º 7
0
func isRangeEmpty(rtr fdb.ReadTransaction, r fdb.Range) bool {
	kvs := rtr.GetRange(r, fdb.RangeOptions{Limit: 1}).GetSliceOrPanic()

	return len(kvs) == 0
}