func (dl directoryLayer) initializeDirectory(tr fdb.Transaction) { buf := new(bytes.Buffer) // bytes.Buffer claims that Write will always return a nil error, which // means the error return here can only be an encoding issue. So long as we // don't set our own versions to something completely invalid, we should be // OK to ignore error returns. binary.Write(buf, binary.LittleEndian, _MAJORVERSION) binary.Write(buf, binary.LittleEndian, _MINORVERSION) binary.Write(buf, binary.LittleEndian, _MICROVERSION) tr.Set(dl.rootNode.Sub([]byte("version")), buf.Bytes()) }
func (dl directoryLayer) subdirNodes(tr fdb.Transaction, node subspace.Subspace) []subspace.Subspace { sd := node.Sub(_SUBDIRS) rr := tr.GetRange(sd, fdb.RangeOptions{}) ri := rr.Iterator() var ret []subspace.Subspace for ri.Advance() { kv := ri.MustGet() ret = append(ret, dl.nodeWithPrefix(kv.Value)) } return ret }
func (dl directoryLayer) removeRecursive(tr fdb.Transaction, node subspace.Subspace) error { nodes := dl.subdirNodes(tr, node) for i := range nodes { if e := dl.removeRecursive(tr, nodes[i]); e != nil { return e } } p, e := dl.nodeSS.Unpack(node) if e != nil { return e } kr, e := fdb.PrefixRange(p[0].([]byte)) if e != nil { return e } tr.ClearRange(kr) tr.ClearRange(node) return nil }
func (hca highContentionAllocator) allocate(tr fdb.Transaction, s subspace.Subspace) (subspace.Subspace, error) { rr := tr.Snapshot().GetRange(hca.counters, fdb.RangeOptions{Limit: 1, Reverse: true}) kvs := rr.GetSliceOrPanic() var start, count int64 if len(kvs) == 1 { t, e := hca.counters.Unpack(kvs[0].Key) if e != nil { return nil, e } start = t[0].(int64) e = binary.Read(bytes.NewBuffer(kvs[0].Value), binary.LittleEndian, &count) if e != nil { return nil, e } } window := windowSize(start) if (count+1)*2 >= window { // Advance the window tr.ClearRange(fdb.KeyRange{hca.counters, append(hca.counters.Sub(start).FDBKey(), 0x00)}) start += window tr.ClearRange(fdb.KeyRange{hca.recent, hca.recent.Sub(start)}) window = windowSize(start) } // Increment the allocation count for the current window tr.Add(hca.counters.Sub(start), oneBytes) for { // As of the snapshot being read from, the window is less than half // full, so this should be expected to take 2 tries. Under high // contention (and when the window advances), there is an additional // subsequent risk of conflict for this transaction. candidate := rand.Int63n(window) + start key := hca.recent.Sub(candidate) if tr.Get(key).MustGet() == nil { tr.Set(key, []byte("")) return s.Sub(candidate), nil } } }
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) }
func (dl directoryLayer) removeFromParent(tr fdb.Transaction, path []string) { parent := dl.find(tr, path[:len(path)-1]) tr.Clear(parent.subspace.Sub(_SUBDIRS, path[len(path)-1])) }