func provideKeysRec(ctx context.Context, r routing.IpfsRouting, dserv dag.DAGService, cids []*cid.Cid) error { provided := cid.NewSet() for _, c := range cids { kset := cid.NewSet() err := dag.EnumerateChildrenAsync(ctx, dserv, c, kset.Visit) if err != nil { return err } for _, k := range kset.Keys() { if provided.Has(k) { continue } err = r.Provide(ctx, k) if err != nil { return err } provided.Add(k) } } return nil }
// NewPinner creates a new pinner using the given datastore as a backend func NewPinner(dstore ds.Datastore, serv, internal mdag.DAGService) Pinner { rcset := cid.NewSet() dirset := cid.NewSet() return &pinner{ recursePin: rcset, directPin: dirset, dserv: serv, dstore: dstore, internal: internal, internalPin: cid.NewSet(), } }
func TestEnumerateChildren(t *testing.T) { bsi := bstest.Mocks(1) ds := NewDAGService(bsi[0]) read := io.LimitReader(u.NewTimeSeededRand(), 1024*1024) root, err := imp.BuildDagFromReader(ds, chunk.NewSizeSplitter(read, 512)) if err != nil { t.Fatal(err) } set := cid.NewSet() err = EnumerateChildren(context.Background(), ds, root.Cid(), set.Visit, false) if err != nil { t.Fatal(err) } var traverse func(n node.Node) traverse = func(n node.Node) { // traverse dag and check for _, lnk := range n.Links() { c := lnk.Cid if !set.Has(c) { t.Fatal("missing key in set! ", lnk.Cid.String()) } child, err := ds.Get(context.Background(), c) if err != nil { t.Fatal(err) } traverse(child) } } traverse(root) }
func cidSetWithValues(cids []*cid.Cid) *cid.Set { out := cid.NewSet() for _, c := range cids { out.Add(c) } return out }
// Remove duplicates from a list of keys func dedupeKeys(cids []*cid.Cid) []*cid.Cid { set := cid.NewSet() for _, c := range cids { set.Add(c) } return set.Keys() }
func SimpleSetFromKeys(keys []*cid.Cid) BlockSet { sbs := &simpleBlockSet{blocks: cid.NewSet()} for _, k := range keys { sbs.AddBlock(k) } return sbs }
func ColoredSet(ctx context.Context, pn pin.Pinner, ls dag.LinkService, bestEffortRoots []*cid.Cid) (*cid.Set, error) { // KeySet currently implemented in memory, in the future, may be bloom filter or // disk backed to conserve memory. gcs := cid.NewSet() err := Descendants(ctx, ls, gcs, pn.RecursiveKeys(), false) if err != nil { return nil, err } err = Descendants(ctx, ls, gcs, bestEffortRoots, true) if err != nil { return nil, err } for _, k := range pn.DirectKeys() { gcs.Add(k) } err = Descendants(ctx, ls, gcs, pn.InternalPins(), false) if err != nil { return nil, err } return gcs, nil }
func pinLsAll(typeStr string, ctx context.Context, n *core.IpfsNode) (map[string]RefKeyObject, error) { keys := make(map[string]RefKeyObject) AddToResultKeys := func(keyList []*cid.Cid, typeStr string) { for _, c := range keyList { keys[c.String()] = RefKeyObject{ Type: typeStr, } } } if typeStr == "direct" || typeStr == "all" { AddToResultKeys(n.Pinning.DirectKeys(), "direct") } if typeStr == "indirect" || typeStr == "all" { set := cid.NewSet() for _, k := range n.Pinning.RecursiveKeys() { err := dag.EnumerateChildren(n.Context(), n.DAG, k, set.Visit, false) if err != nil { return nil, err } } AddToResultKeys(set.Keys(), "indirect") } if typeStr == "recursive" || typeStr == "all" { AddToResultKeys(n.Pinning.RecursiveKeys(), "recursive") } return keys, nil }
// LoadPinner loads a pinner and its keysets from the given datastore func LoadPinner(d ds.Datastore, dserv, internal mdag.DAGService) (Pinner, error) { p := new(pinner) rootKeyI, err := d.Get(pinDatastoreKey) if err != nil { return nil, fmt.Errorf("cannot load pin state: %v", err) } rootKeyBytes, ok := rootKeyI.([]byte) if !ok { return nil, fmt.Errorf("cannot load pin state: %s was not bytes", pinDatastoreKey) } rootCid, err := cid.Cast(rootKeyBytes) if err != nil { return nil, err } ctx, cancel := context.WithTimeout(context.TODO(), time.Second*5) defer cancel() root, err := internal.Get(ctx, rootCid) if err != nil { return nil, fmt.Errorf("cannot find pinning root object: %v", err) } rootpb, ok := root.(*mdag.ProtoNode) if !ok { return nil, mdag.ErrNotProtobuf } internalset := cid.NewSet() internalset.Add(rootCid) recordInternal := internalset.Add { // load recursive set recurseKeys, err := loadSet(ctx, internal, rootpb, linkRecursive, recordInternal) if err != nil { return nil, fmt.Errorf("cannot load recursive pins: %v", err) } p.recursePin = cidSetWithValues(recurseKeys) } { // load direct set directKeys, err := loadSet(ctx, internal, rootpb, linkDirect, recordInternal) if err != nil { return nil, fmt.Errorf("cannot load direct pins: %v", err) } p.directPin = cidSetWithValues(directKeys) } p.internalPin = internalset // assign services p.dserv = dserv p.dstore = d p.internal = internal return p, nil }
func TestSet(t *testing.T) { ds := mdtest.Mock() limit := 10000 // 10000 reproduces the pinloss issue fairly reliably if os.Getenv("STRESS_IT_OUT_YO") != "" { limit = 10000000 } var inputs []*cid.Cid for i := 0; i < limit; i++ { c, err := ds.Add(dag.NodeWithData([]byte(fmt.Sprint(i)))) if err != nil { t.Fatal(err) } inputs = append(inputs, c) } out, err := storeSet(context.Background(), ds, inputs, ignoreCids) if err != nil { t.Fatal(err) } // weird wrapper node because loadSet expects us to pass an // object pointing to multiple named sets setroot := &dag.ProtoNode{} err = setroot.AddNodeLinkClean("foo", out) if err != nil { t.Fatal(err) } outset, err := loadSet(context.Background(), ds, setroot, "foo", ignoreCids) if err != nil { t.Fatal(err) } if len(outset) != limit { t.Fatal("got wrong number", len(outset), limit) } seen := cid.NewSet() for _, c := range outset { seen.Add(c) } for _, c := range inputs { if !seen.Has(c) { t.Fatalf("expected to have %s, didnt find it") } } }
// skip returns whether to skip a cid func (rw *RefWriter) skip(c *cid.Cid) bool { if !rw.Unique { return false } if rw.seen == nil { rw.seen = cid.NewSet() } has := rw.seen.Has(c) if !has { rw.seen.Add(c) } return has }
// Flush encodes and writes pinner keysets to the datastore func (p *pinner) Flush() error { p.lock.Lock() defer p.lock.Unlock() ctx := context.TODO() internalset := cid.NewSet() recordInternal := internalset.Add root := &mdag.ProtoNode{} { n, err := storeSet(ctx, p.internal, p.directPin.Keys(), recordInternal) if err != nil { return err } if err := root.AddNodeLink(linkDirect, n); err != nil { return err } } { n, err := storeSet(ctx, p.internal, p.recursePin.Keys(), recordInternal) if err != nil { return err } if err := root.AddNodeLink(linkRecursive, n); err != nil { return err } } // add the empty node, its referenced by the pin sets but never created _, err := p.internal.Add(new(mdag.ProtoNode)) if err != nil { return err } k, err := p.internal.Add(root) if err != nil { return err } internalset.Add(k) if err := p.dstore.Put(pinDatastoreKey, k.Bytes()); err != nil { return fmt.Errorf("cannot store pin state: %v", err) } p.internalPin = internalset return nil }
func (bs *Bitswap) providerQueryManager(ctx context.Context) { var activeLk sync.Mutex kset := cid.NewSet() for { select { case e := <-bs.findKeys: activeLk.Lock() if kset.Has(e.Cid) { activeLk.Unlock() continue } kset.Add(e.Cid) activeLk.Unlock() go func(e *blockRequest) { child, cancel := context.WithTimeout(e.Ctx, providerRequestTimeout) defer cancel() providers := bs.network.FindProvidersAsync(child, e.Cid, maxProvidersPerRequest) wg := &sync.WaitGroup{} for p := range providers { wg.Add(1) go func(p peer.ID) { defer wg.Done() err := bs.network.ConnectTo(child, p) if err != nil { log.Debug("failed to connect to provider %s: %s", p, err) } }(p) } wg.Wait() activeLk.Lock() kset.Remove(e.Cid) activeLk.Unlock() }(e) case <-ctx.Done(): return } } }
func TestAddGCLive(t *testing.T) { r := &repo.Mock{ C: config.Config{ Identity: config.Identity{ PeerID: "Qmfoo", // required by offline node }, }, D: testutil.ThreadSafeCloserMapDatastore(), } node, err := core.NewNode(context.Background(), &core.BuildCfg{Repo: r}) if err != nil { t.Fatal(err) } errs := make(chan error) out := make(chan interface{}) adder, err := NewAdder(context.Background(), node.Pinning, node.Blockstore, node.DAG) if err != nil { t.Fatal(err) } adder.Out = out dataa := ioutil.NopCloser(bytes.NewBufferString("testfileA")) rfa := files.NewReaderFile("a", "a", dataa, nil) // make two files with pipes so we can 'pause' the add for timing of the test piper, pipew := io.Pipe() hangfile := files.NewReaderFile("b", "b", piper, nil) datad := ioutil.NopCloser(bytes.NewBufferString("testfileD")) rfd := files.NewReaderFile("d", "d", datad, nil) slf := files.NewSliceFile("files", "files", []files.File{rfa, hangfile, rfd}) addDone := make(chan struct{}) go func() { defer close(addDone) defer close(out) err := adder.AddFile(slf) if err != nil { t.Fatal(err) } }() addedHashes := make(map[string]struct{}) select { case o := <-out: addedHashes[o.(*AddedObject).Hash] = struct{}{} case <-addDone: t.Fatal("add shouldnt complete yet") } var gcout <-chan *cid.Cid gcstarted := make(chan struct{}) go func() { defer close(gcstarted) gcchan, err := gc.GC(context.Background(), node.Blockstore, node.DAG, node.Pinning, nil) if err != nil { log.Error("GC ERROR:", err) errs <- err return } gcout = gcchan }() // gc shouldnt start until we let the add finish its current file. pipew.Write([]byte("some data for file b")) select { case <-gcstarted: t.Fatal("gc shouldnt have started yet") case err := <-errs: t.Fatal(err) default: } time.Sleep(time.Millisecond * 100) // make sure gc gets to requesting lock // finish write and unblock gc pipew.Close() // receive next object from adder select { case o := <-out: addedHashes[o.(*AddedObject).Hash] = struct{}{} case err := <-errs: t.Fatal(err) } select { case <-gcstarted: case err := <-errs: t.Fatal(err) } for k := range gcout { if _, ok := addedHashes[k.String()]; ok { t.Fatal("gc'ed a hash we just added") } } var last *cid.Cid for a := range out { // wait for it to finish c, err := cid.Decode(a.(*AddedObject).Hash) if err != nil { t.Fatal(err) } last = c } ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel() set := cid.NewSet() err = dag.EnumerateChildren(ctx, node.DAG, last, set.Visit, false) if err != nil { t.Fatal(err) } }
// GetBlocks returns a channel where the caller may receive blocks that // correspond to the provided |keys|. Returns an error if BitSwap is unable to // begin this request within the deadline enforced by the context. // // NB: Your request remains open until the context expires. To conserve // resources, provide a context with a reasonably short deadline (ie. not one // that lasts throughout the lifetime of the server) func (bs *Bitswap) GetBlocks(ctx context.Context, keys []*cid.Cid) (<-chan blocks.Block, error) { if len(keys) == 0 { out := make(chan blocks.Block) close(out) return out, nil } select { case <-bs.process.Closing(): return nil, errors.New("bitswap is closed") default: } promise := bs.notifications.Subscribe(ctx, keys...) for _, k := range keys { log.Event(ctx, "Bitswap.GetBlockRequest.Start", k) } bs.wm.WantBlocks(ctx, keys) // NB: Optimization. Assumes that providers of key[0] are likely to // be able to provide for all keys. This currently holds true in most // every situation. Later, this assumption may not hold as true. req := &blockRequest{ Cid: keys[0], Ctx: ctx, } remaining := cid.NewSet() for _, k := range keys { remaining.Add(k) } out := make(chan blocks.Block) go func() { ctx, cancel := context.WithCancel(ctx) defer cancel() defer close(out) defer func() { // can't just defer this call on its own, arguments are resolved *when* the defer is created bs.CancelWants(remaining.Keys()) }() for { select { case blk, ok := <-promise: if !ok { return } remaining.Remove(blk.Cid()) select { case out <- blk: case <-ctx.Done(): return } case <-ctx.Done(): return } } }() select { case bs.findKeys <- req: return out, nil case <-ctx.Done(): return nil, ctx.Err() } }
// FetchGraph fetches all nodes that are children of the given node func FetchGraph(ctx context.Context, c *cid.Cid, serv DAGService) error { return EnumerateChildrenAsync(ctx, serv, c, cid.NewSet().Visit) }
func NewSimpleBlockSet() BlockSet { return &simpleBlockSet{blocks: cid.NewSet()} }
func (p *pinner) CheckIfPinned(cids ...*cid.Cid) ([]Pinned, error) { p.lock.RLock() defer p.lock.RUnlock() pinned := make([]Pinned, 0, len(cids)) toCheck := cid.NewSet() // First check for non-Indirect pins directly for _, c := range cids { if p.recursePin.Has(c) { pinned = append(pinned, Pinned{Key: c, Mode: Recursive}) } else if p.directPin.Has(c) { pinned = append(pinned, Pinned{Key: c, Mode: Direct}) } else if p.isInternalPin(c) { pinned = append(pinned, Pinned{Key: c, Mode: Internal}) } else { toCheck.Add(c) } } // Now walk all recursive pins to check for indirect pins var checkChildren func(*cid.Cid, *cid.Cid) error checkChildren = func(rk, parentKey *cid.Cid) error { links, err := p.dserv.GetLinks(context.Background(), parentKey) if err != nil { return err } for _, lnk := range links { c := lnk.Cid if toCheck.Has(c) { pinned = append(pinned, Pinned{Key: c, Mode: Indirect, Via: rk}) toCheck.Remove(c) } err := checkChildren(rk, c) if err != nil { return err } if toCheck.Len() == 0 { return nil } } return nil } for _, rk := range p.recursePin.Keys() { err := checkChildren(rk, rk) if err != nil { return nil, err } if toCheck.Len() == 0 { break } } // Anything left in toCheck is not pinned for _, k := range toCheck.Keys() { pinned = append(pinned, Pinned{Key: k, Mode: NotPinned}) } return pinned, nil }