func (ks *DSSuite) TestBasic(c *C) { var size = 1000 d, err := lru.NewDatastore(size) c.Check(err, Equals, nil) for i := 0; i < size; i++ { err := d.Put(ds.NewKey(strconv.Itoa(i)), i) c.Check(err, Equals, nil) } for i := 0; i < size; i++ { j, err := d.Get(ds.NewKey(strconv.Itoa(i))) c.Check(j, Equals, i) c.Check(err, Equals, nil) } for i := 0; i < size; i++ { err := d.Put(ds.NewKey(strconv.Itoa(i+size)), i) c.Check(err, Equals, nil) } for i := 0; i < size; i++ { j, err := d.Get(ds.NewKey(strconv.Itoa(i))) c.Check(j, Equals, nil) c.Check(err, Equals, ds.ErrNotFound) } for i := 0; i < size; i++ { j, err := d.Get(ds.NewKey(strconv.Itoa(i + size))) c.Check(j, Equals, i) c.Check(err, Equals, nil) } }
func TestCoalesceSamePutDiffPut(t *testing.T) { m := setup() done := make(chan struct{}) go func() { m.ds.Put(ds.NewKey("foo"), "bar") done <- struct{}{} }() go func() { m.ds.Put(ds.NewKey("foo"), "bar") done <- struct{}{} }() go func() { m.ds.Put(ds.NewKey("foo"), "bar2") done <- struct{}{} }() go func() { m.ds.Put(ds.NewKey("foo"), "bar3") done <- struct{}{} }() <-done <-done <-done <-done if m.inside != 3 { t.Error("incalls should be 3", m.inside) } if m.outside != 4 { t.Error("outcalls should be 4", m.outside) } }
func TestCoalesceHas(t *testing.T) { m := setup() done := make(chan struct{}) errs := make(chan error, 30) m.ds.Put(ds.NewKey("foo1"), "bar") m.ds.Put(ds.NewKey("foo2"), "baz") for i := 0; i < 10; i++ { go func() { v, err := m.ds.Has(ds.NewKey("foo1")) if err != nil { errs <- err } if !v { errs <- fmt.Errorf("should have foo1") } done <- struct{}{} }() } for i := 0; i < 10; i++ { go func() { v, err := m.ds.Has(ds.NewKey("foo2")) if err != nil { errs <- err } if !v { errs <- fmt.Errorf("should have foo2") } done <- struct{}{} }() } for i := 0; i < 10; i++ { go func() { v, err := m.ds.Has(ds.NewKey("foo3")) if err != nil { errs <- err } if v { errs <- fmt.Errorf("should not have foo3") } done <- struct{}{} }() } for i := 0; i < 30; i++ { <-done } if m.inside != 5 { t.Error("incalls should be 3", m.inside) } if m.outside != 32 { t.Error("outcalls should be 30", m.outside) } }
func TestCoalesceSameGet(t *testing.T) { m := setup() done := make(chan struct{}) errs := make(chan error, 30) m.ds.Put(ds.NewKey("foo1"), "bar") m.ds.Put(ds.NewKey("foo2"), "baz") for i := 0; i < 10; i++ { go func() { v, err := m.ds.Get(ds.NewKey("foo1")) if err != nil { errs <- err } if v != "bar" { errs <- fmt.Errorf("v is not bar", v) } done <- struct{}{} }() } for i := 0; i < 10; i++ { go func() { v, err := m.ds.Get(ds.NewKey("foo2")) if err != nil { errs <- err } if v != "baz" { errs <- fmt.Errorf("v is not baz", v) } done <- struct{}{} }() } for i := 0; i < 10; i++ { go func() { _, err := m.ds.Get(ds.NewKey("foo3")) if err == nil { errs <- fmt.Errorf("no error") } done <- struct{}{} }() } for i := 0; i < 30; i++ { <-done } if m.inside != 5 { t.Error("incalls should be 3", m.inside) } if m.outside != 32 { t.Error("outcalls should be 30", m.outside) } }
func (d *Datastore) lookup(key ds.Key) (ds.Datastore, ds.Key, ds.Key) { d.lk.Lock() defer d.lk.Unlock() for _, m := range d.mounts { if m.Prefix.Equal(key) || m.Prefix.IsAncestorOf(key) { s := strings.TrimPrefix(key.String(), m.Prefix.String()) k := ds.NewKey(s) return m.Datastore, m.Prefix, k } } return nil, ds.NewKey("/"), key }
func (ks *DSSuite) TestBasic(c *C) { mpds := ds.NewMapDatastore() nsds := ns.Wrap(mpds, ds.NewKey("abc")) keys := strsToKeys([]string{ "foo", "foo/bar", "foo/bar/baz", "foo/barb", "foo/bar/bazb", "foo/bar/baz/barb", }) for _, k := range keys { err := nsds.Put(k, []byte(k.String())) c.Check(err, Equals, nil) } for _, k := range keys { v1, err := nsds.Get(k) c.Check(err, Equals, nil) c.Check(bytes.Equal(v1.([]byte), []byte(k.String())), Equals, true) v2, err := mpds.Get(ds.NewKey("abc").Child(k)) c.Check(err, Equals, nil) c.Check(bytes.Equal(v2.([]byte), []byte(k.String())), Equals, true) } run := func(d ds.Datastore, q dsq.Query) []ds.Key { r, err := d.Query(q) c.Check(err, Equals, nil) e, err := r.Rest() c.Check(err, Equals, nil) return ds.EntryKeys(e) } listA := run(mpds, dsq.Query{}) listB := run(nsds, dsq.Query{}) c.Check(len(listA), Equals, len(listB)) // sort them cause yeah. sort.Sort(ds.KeySlice(listA)) sort.Sort(ds.KeySlice(listB)) for i, kA := range listA { kB := listB[i] c.Check(nsds.InvertKey(kA), Equals, kB) c.Check(kA, Equals, nsds.ConvertKey(kB)) } }
// Query implements Datastore.Query func (d *Datastore) Query(q query.Query) (query.Results, error) { results := make(chan query.Result) walkFn := func(path string, info os.FileInfo, err error) error { // remove ds path prefix if strings.HasPrefix(path, d.path) { path = path[len(d.path):] } if !info.IsDir() { if strings.HasSuffix(path, ObjectKeySuffix) { path = path[:len(path)-len(ObjectKeySuffix)] } key := ds.NewKey(path) entry := query.Entry{Key: key.String(), Value: query.NotFetched} results <- query.Result{Entry: entry} } return nil } go func() { filepath.Walk(d.path, walkFn) close(results) }() r := query.ResultsWithChan(q, results) r = query.NaiveQueryApply(q, r) return r, nil }
// Query implements Query, inverting keys on the way back out. func (d *datastore) Query(q dsq.Query) (dsq.Results, error) { qr, err := d.raw.Query(q) if err != nil { return nil, err } ch := make(chan dsq.Result) go func() { defer close(ch) defer qr.Close() for r := range qr.Next() { if r.Error != nil { ch <- r continue } k := ds.NewKey(r.Entry.Key) if !d.prefix.IsAncestorOf(k) { continue } r.Entry.Key = d.Datastore.InvertKey(k).String() ch <- r } }() return dsq.DerivedResults(qr, ch), nil }
func strsToKeys(strs []string) []ds.Key { keys := make([]ds.Key, len(strs)) for i, s := range strs { keys[i] = ds.NewKey(s) } return keys }
// ConvertKey returns a B58 encoded Datastore key // TODO: this is hacky because it encodes every path component. some // path components may be proper strings already... func (b58KeyConverter) ConvertKey(dsk ds.Key) ds.Key { k := ds.NewKey("/") for _, n := range dsk.Namespaces() { k = k.ChildString(b58.Encode([]byte(n))) } return k }
func BenchmarkPutMany(b *testing.B) { b.StopTimer() path, err := ioutil.TempDir("/tmp", "boltdbtest") db, err := NewBoltDatastore(path, "test") if err != nil { b.Fatal(err) } values := make(map[string][]byte) for i := 0; i < b.N; i++ { values[fmt.Sprint(i)] = []byte(fmt.Sprintf("value number %d", i)) } b.StartTimer() data := make(map[ds.Key]interface{}) for k, v := range values { dsk := ds.NewKey(k) data[dsk] = v } err = db.PutMany(data) if err != nil { b.Fatal(err) } }
func TestBasicPutGet(t *testing.T) { path, err := ioutil.TempDir("/tmp", "boltdbtest") db, err := NewBoltDatastore(path, "test") if err != nil { t.Fatal(err) } dsk := ds.NewKey("test") somedata := []byte("some data in the datastore") err = db.Put(dsk, somedata) if err != nil { t.Fatal(err) } val, err := db.Get(dsk) if err != nil { t.Fatal(err) } b, ok := val.([]byte) if !ok { t.Fatal("Got back invalid typed data") } if !bytes.Equal(b, somedata) { t.Fatal("wrong data") } err = db.Close() if err != nil { t.Fatal(err) } }
// Put adds a record to the record.Store. Multiple records // may be put at once to the same path. // In networked Stores, this may be a blocking operation. // Some Stores may enforce strict consistency, others may be // eventually consistent, and some might simply be best effort. func (s *Store) Put(ctx cxt.Context, p store.Path, r record.Record) error { k := ds.NewKey(string(p)) m, err := record.Marshal(r) if err != nil { return err } return s.ds.Put(k, m) }
func (bd *boltDatastore) Query(q query.Query) (query.Results, error) { qrb := query.NewResultBuilder(q) qrb.Process.Go(func(worker goprocess.Process) { bd.db.View(func(tx *bolt.Tx) error { buck := tx.Bucket(bd.bucketName) c := buck.Cursor() var prefix []byte if qrb.Query.Prefix != "" { prefix = []byte(qrb.Query.Prefix) } cur := 0 sent := 0 for k, v := c.Seek(prefix); k != nil; k, v = c.Next() { if cur < qrb.Query.Offset { cur++ continue } if qrb.Query.Limit > 0 && sent >= qrb.Query.Limit { break } dk := ds.NewKey(string(k)).String() e := query.Entry{Key: dk} if !qrb.Query.KeysOnly { buf := make([]byte, len(v)) copy(buf, v) e.Value = buf } select { case qrb.Output <- query.Result{Entry: e}: // we sent it out sent++ case <-worker.Closing(): // client told us to end early. break } cur++ } return nil }) }) // go wait on the worker (without signaling close) go qrb.Process.CloseAfterChildren() qr := qrb.Results() for _, f := range q.Filters { qr = query.NaiveFilter(qr, f) } for _, o := range q.Orders { qr = query.NaiveOrder(qr, o) } return qr, nil }
func (mt *mountBatch) lookupBatch(key ds.Key) (ds.Batch, ds.Key, error) { mt.lk.Lock() defer mt.lk.Unlock() child, loc, rest := mt.d.lookup(key) t, ok := mt.mounts[loc.String()] if !ok { bds, ok := child.(ds.Batching) if !ok { return nil, ds.NewKey(""), ds.ErrBatchUnsupported } var err error t, err = bds.Batch() if err != nil { return nil, ds.NewKey(""), err } mt.mounts[loc.String()] = t } return t, rest, nil }
func addTestCases(t *testing.T, d *datastore, testcases map[string]string) { for k, v := range testcases { dsk := ds.NewKey(k) if err := d.Put(dsk, []byte(v)); err != nil { t.Fatal(err) } } for k, v := range testcases { dsk := ds.NewKey(k) v2, err := d.Get(dsk) if err != nil { t.Fatal(err) } v2b := v2.([]byte) if string(v2b) != v { t.Errorf("%s values differ: %s != %s", k, v, v2) } } }
func Example() { mp := ds.NewMapDatastore() ns := nsds.Wrap(mp, ds.NewKey("/foo/bar")) k := ds.NewKey("/beep") v := "boop" ns.Put(k, v) fmt.Printf("ns.Put %s %s\n", k, v) v2, _ := ns.Get(k) fmt.Printf("ns.Get %s -> %s\n", k, v2) k3 := ds.NewKey("/foo/bar/beep") v3, _ := mp.Get(k3) fmt.Printf("mp.Get %s -> %s\n", k3, v3) // Output: // ns.Put /beep boop // ns.Get /beep -> boop // mp.Get /foo/bar/beep -> boop }
// Get retrieves the "best" record for a given path from the // record.Store. Determining the "best" record is based on // the total ordering of records, given by record.Order(). // In networked Stores, this may be a blocking operation. // Some Stores may enforce strict consistency, others may be // eventually consistent, and some might simply be best effort. func (s *Store) Get(ctx cxt.Context, p store.Path) (record.Record, error) { k := ds.NewKey(string(p)) m, err := s.ds.Get(k) if err != nil { return nil, err } d, ok := m.([]byte) if !ok { return nil, fmt.Errorf("invalid datastore data (not a buffer)") } return record.UnmarshalFromSet(s.ts, d) }
func RunBatchTest(t *testing.T, ds dstore.Batching) { batch, err := ds.Batch() if err != nil { t.Fatal(err) } r := rand.New() var blocks [][]byte var keys []dstore.Key for i := 0; i < 20; i++ { blk := make([]byte, 256*1024) r.Read(blk) blocks = append(blocks, blk) key := dstore.NewKey(base32.StdEncoding.EncodeToString(blk[:8])) keys = append(keys, key) err := batch.Put(key, blk) if err != nil { t.Fatal(err) } } // Ensure they are not in the datastore before comitting for _, k := range keys { _, err := ds.Get(k) if err == nil { t.Fatal("should not have found this block") } } // commit, write them to the datastore err = batch.Commit() if err != nil { t.Fatal(err) } for i, k := range keys { blk, err := ds.Get(k) if err != nil { t.Fatal(err) } if !bytes.Equal(blk.([]byte), blocks[i]) { t.Fatal("blocks not correct!") } } }
func (d *datastore) runQuery(worker goprocess.Process, qrb *dsq.ResultBuilder) { var rnge *util.Range if qrb.Query.Prefix != "" { rnge = util.BytesPrefix([]byte(qrb.Query.Prefix)) } i := d.DB.NewIterator(rnge, nil) defer i.Release() // advance iterator for offset if qrb.Query.Offset > 0 { for j := 0; j < qrb.Query.Offset; j++ { i.Next() } } // iterate, and handle limit, too for sent := 0; i.Next(); sent++ { // end early if we hit the limit if qrb.Query.Limit > 0 && sent >= qrb.Query.Limit { break } k := ds.NewKey(string(i.Key())).String() e := dsq.Entry{Key: k} if !qrb.Query.KeysOnly { buf := make([]byte, len(i.Value())) copy(buf, i.Value()) e.Value = buf } select { case qrb.Output <- dsq.Result{Entry: e}: // we sent it out case <-worker.Closing(): // client told us to end early. break } } if err := i.Error(); err != nil { select { case qrb.Output <- dsq.Result{Error: err}: // client read our error case <-worker.Closing(): // client told us to end. return } } }
// PrefixTransform constructs a KeyTransform with a pair of functions that // add or remove the given prefix key. // // Warning: will panic if prefix not found when it should be there. This is // to avoid insidious data inconsistency errors. func PrefixTransform(prefix ds.Key) ktds.KeyTransform { return &ktds.Pair{ // Convert adds the prefix Convert: func(k ds.Key) ds.Key { return prefix.Child(k) }, // Invert removes the prefix. panics if prefix not found. Invert: func(k ds.Key) ds.Key { if !prefix.IsAncestorOf(k) { fmt.Errorf("Expected prefix (%s) in key (%s)", prefix, k) panic("expected prefix not found") } s := strings.TrimPrefix(k.String(), prefix.String()) return ds.NewKey(s) }, } }
// Query implements Query, inverting keys on the way back out. func (d *ktds) Query(q dsq.Query) (dsq.Results, error) { qr, err := d.child.Query(q) if err != nil { return nil, err } ch := make(chan dsq.Result) go func() { defer close(ch) defer qr.Close() for r := range qr.Next() { if r.Error == nil { r.Entry.Key = d.InvertKey(ds.NewKey(r.Entry.Key)).String() } ch <- r } }() return dsq.DerivedResults(qr, ch), nil }
func RunBatchDeleteTest(t *testing.T, ds dstore.Batching) { r := rand.New() var keys []dstore.Key for i := 0; i < 20; i++ { blk := make([]byte, 16) r.Read(blk) key := dstore.NewKey(base32.StdEncoding.EncodeToString(blk[:8])) keys = append(keys, key) err := ds.Put(key, blk) if err != nil { t.Fatal(err) } } batch, err := ds.Batch() if err != nil { t.Fatal(err) } for _, k := range keys { err := batch.Delete(k) if err != nil { t.Fatal(err) } } err = batch.Commit() if err != nil { t.Fatal(err) } for _, k := range keys { _, err := ds.Get(k) if err == nil { t.Fatal("shouldnt have found block") } } }
func (d *Datastore) Query(q query.Query) (query.Results, error) { if len(q.Filters) > 0 || len(q.Orders) > 0 || q.Limit > 0 || q.Offset > 0 { // TODO this is overly simplistic, but the only caller is // `ipfs refs local` for now, and this gets us moving. return nil, errors.New("mount only supports listing all prefixed keys in random order") } key := ds.NewKey(q.Prefix) cds, mount, k := d.lookup(key) if cds == nil { return nil, errors.New("mount only supports listing a mount point") } // TODO support listing cross mount points too // delegate the query to the mounted datastore, while adjusting // keys in and out q2 := q q2.Prefix = k.String() wrapDS := keytransform.Wrap(cds, &keytransform.Pair{ Convert: func(ds.Key) ds.Key { panic("this should never be called") }, Invert: func(k ds.Key) ds.Key { return mount.Child(k) }, }) r, err := wrapDS.Query(q2) if err != nil { return nil, err } r = query.ResultsReplaceQuery(r, q) return r, nil }
func TestTimeCache(t *testing.T) { ttl := time.Millisecond * 100 cache := WithTTL(ttl) cache.Put(ds.NewKey("foo1"), "bar1") cache.Put(ds.NewKey("foo2"), "bar2") <-time.After(ttl / 2) cache.Put(ds.NewKey("foo3"), "bar3") cache.Put(ds.NewKey("foo4"), "bar4") testHas(t, cache, ds.NewKey("foo1"), "bar1") testHas(t, cache, ds.NewKey("foo2"), "bar2") testHas(t, cache, ds.NewKey("foo3"), "bar3") testHas(t, cache, ds.NewKey("foo4"), "bar4") <-time.After(ttl / 2) testNotHas(t, cache, ds.NewKey("foo1")) testNotHas(t, cache, ds.NewKey("foo2")) testHas(t, cache, ds.NewKey("foo3"), "bar3") testHas(t, cache, ds.NewKey("foo4"), "bar4") cache.Delete(ds.NewKey("foo3")) testNotHas(t, cache, ds.NewKey("foo3")) <-time.After(ttl / 2) testNotHas(t, cache, ds.NewKey("foo1")) testNotHas(t, cache, ds.NewKey("foo2")) testNotHas(t, cache, ds.NewKey("foo3")) testNotHas(t, cache, ds.NewKey("foo4")) }
// DsKey returns a Datastore key func (k Key) DsKey() ds.Key { return ds.NewKey(string(k)) }
func (ps *peerstore) Get(p ID, key string) (interface{}, error) { dsk := ds.NewKey(string(p) + "/" + key) return ps.ds.Get(dsk) }
func (ps *peerstore) Put(p ID, key string, val interface{}) error { dsk := ds.NewKey(string(p) + "/" + key) return ps.ds.Put(dsk, val) }
func TestCoalesceDelete(t *testing.T) { m := setup() done := make(chan struct{}) errs := make(chan error, 30) m.ds.Put(ds.NewKey("foo1"), "bar1") m.ds.Put(ds.NewKey("foo2"), "bar2") m.ds.Put(ds.NewKey("foo3"), "bar3") for i := 0; i < 10; i++ { go func() { err := m.ds.Delete(ds.NewKey("foo1")) if err != nil { errs <- err } has, err := m.ds.Has(ds.NewKey("foo1")) if err != nil { errs <- err } if has { t.Error("still have it after deleting") } done <- struct{}{} }() } for i := 0; i < 10; i++ { go func() { err := m.ds.Delete(ds.NewKey("foo2")) if err != nil { errs <- err } has, err := m.ds.Has(ds.NewKey("foo2")) if err != nil { errs <- err } if has { t.Error("still have it after deleting") } done <- struct{}{} }() } for i := 0; i < 10; i++ { go func() { has, err := m.ds.Has(ds.NewKey("foo3")) if err != nil { errs <- err } if !has { t.Error("should still have foo3") } done <- struct{}{} }() } for i := 0; i < 10; i++ { go func() { has, err := m.ds.Has(ds.NewKey("foo4")) if err != nil { errs <- err } if has { t.Error("should not have foo4") } done <- struct{}{} }() } for i := 0; i < 40; i++ { <-done } if m.inside != 9 { t.Error("incalls should be 9", m.inside) } if m.outside != 63 { t.Error("outcalls should be 63", m.outside) } }
func (ks *DSSuite) TestBasic(c *C) { pair := &kt.Pair{ Convert: func(k ds.Key) ds.Key { return ds.NewKey("/abc").Child(k) }, Invert: func(k ds.Key) ds.Key { // remove abc prefix l := k.List() if l[0] != "abc" { panic("key does not have prefix. convert failed?") } return ds.KeyWithNamespaces(l[1:]) }, } mpds := ds.NewMapDatastore() ktds := kt.Wrap(mpds, pair) keys := strsToKeys([]string{ "foo", "foo/bar", "foo/bar/baz", "foo/barb", "foo/bar/bazb", "foo/bar/baz/barb", }) for _, k := range keys { err := ktds.Put(k, []byte(k.String())) c.Check(err, Equals, nil) } for _, k := range keys { v1, err := ktds.Get(k) c.Check(err, Equals, nil) c.Check(bytes.Equal(v1.([]byte), []byte(k.String())), Equals, true) v2, err := mpds.Get(ds.NewKey("abc").Child(k)) c.Check(err, Equals, nil) c.Check(bytes.Equal(v2.([]byte), []byte(k.String())), Equals, true) } run := func(d ds.Datastore, q dsq.Query) []ds.Key { r, err := d.Query(q) c.Check(err, Equals, nil) e, err := r.Rest() c.Check(err, Equals, nil) return ds.EntryKeys(e) } listA := run(mpds, dsq.Query{}) listB := run(ktds, dsq.Query{}) c.Check(len(listA), Equals, len(listB)) // sort them cause yeah. sort.Sort(ds.KeySlice(listA)) sort.Sort(ds.KeySlice(listB)) for i, kA := range listA { kB := listB[i] c.Check(pair.Invert(kA), Equals, kB) c.Check(kA, Equals, pair.Convert(kB)) } c.Log("listA: ", listA) c.Log("listB: ", listB) }