// Clone is like Get but clones the chunk if it's not already private. // Chunks that are already private are returned as-is. // // A cloned chunk will have a buffer of size bytes. This is intended // to use for re-inflating zero-trimmed chunks. // // Modifying the returned chunk *will* cause the locally stored data // to change. This is the intended usage of a stash. func (s *Stash) Clone(key cas.Key, typ string, level uint8, size uint32) (cas.Key, *chunks.Chunk, error) { priv, ok := key.Private() if ok { chunk, ok := s.local[priv] if !ok { return key, nil, cas.NotFound{ Type: typ, Level: level, Key: key, } } return key, chunk, nil } chunk, err := s.chunks.Get(key, typ, level) if err != nil { return key, nil, err } // clone the byte slice tmp := make([]byte, size) copy(tmp, chunk.Buf) chunk.Buf = tmp priv = s.ids.Get() privkey := cas.NewKeyPrivateNum(priv) s.local[priv] = chunk return privkey, chunk, nil }
func (blob *Blob) saveChunk(key cas.Key, level uint8) (cas.Key, error) { if !key.IsPrivate() { // already saved return key, nil } chunk, err := blob.stash.Get(key, blob.m.Type, level) if err != nil { return key, err } if level > 0 { for off := uint32(0); off+cas.KeySize <= uint32(len(chunk.Buf)); off += cas.KeySize { cur := cas.NewKeyPrivate(chunk.Buf[off : off+cas.KeySize]) if cur.IsReserved() { return key, fmt.Errorf("invalid stored key: key @%d in %v is %v", off, key, chunk.Buf[off:off+cas.KeySize]) } // recurses at most `level` deep saved, err := blob.saveChunk(cur, level-1) if err != nil { return key, err } copy(chunk.Buf[off:off+cas.KeySize], saved.Bytes()) } } chunk.Buf = trim(chunk.Buf) return blob.stash.Save(key) }
// Drop forgets a Private chunk. The key may be reused, so caller must // not remember the old key. func (s *Stash) Drop(key cas.Key) { priv, ok := key.Private() if !ok { return } s.drop(priv) }
func HandleGet(fn Handler, key cas.Key, typ string, level uint8) (*chunks.Chunk, error) { if key.IsSpecial() { if key == cas.Empty { chunk := MakeChunk(typ, level, nil) return chunk, nil } return nil, cas.NotFound{ Type: typ, Level: level, Key: key, } } data, err := fn(key, typ, level) if err != nil { return nil, err } if data == nil { return nil, cas.NotFound{ Type: typ, Level: level, Key: key, } } chunk := MakeChunk(typ, level, data) return chunk, nil }
func makeKey(key cas.Key, typ string, level uint8) []byte { k := make([]byte, 0, cas.KeySize+len(typ)+1) k = append(k, key.Bytes()...) k = append(k, typ...) k = append(k, level) return k }
func (m *Manifest) ToBlob(type_ string) (*blobs.Manifest, error) { var k cas.Key if err := k.UnmarshalBinary(m.Root); err != nil { return nil, err } manifest := &blobs.Manifest{ Type: type_, Root: k, Size: m.Size, ChunkSize: m.ChunkSize, Fanout: m.Fanout, } return manifest, nil }
func TestKeyUnmarshalBinaryBadLong(t *testing.T) { KEY := strings.Repeat("borketyBorkBORK!", 4) + "x" buf := []byte(KEY) var k cas.Key err := k.UnmarshalBinary(buf) if err == nil { t.Fatalf("unmarshal should have failed: %v", k) } e, ok := err.(*cas.BadKeySizeError) if !ok { t.Fatalf("unmarshal error is of wrong type: %T: %v", err, err) } if g, w := string(e.Key), KEY; g != w { t.Errorf("BadKeySizeError Key is wrong: %x != %x", g, w) } }
// Get returns a chunk either from the local stash, or from the // Store (for Private keys). // // For Private keys, modifying the returned chunk *will* cause the // locally stored data to change. This is the intended usage of a // stash. func (s *Stash) Get(key cas.Key, typ string, level uint8) (*chunks.Chunk, error) { priv, ok := key.Private() if ok { chunk, ok := s.local[priv] if !ok { return nil, cas.NotFound{ Type: typ, Level: level, Key: key, } } return chunk, nil } chunk, err := s.chunks.Get(key, typ, level) return chunk, err }
func (d *listSnaps) Lookup(ctx context.Context, name string) (fs.Node, error) { var ref wire.SnapshotRef lookup := func(tx *db.Tx) error { bucket := d.fs.bucket(tx).SnapBucket() if bucket == nil { return errors.New("snapshot bucket missing") } buf := bucket.Get([]byte(name)) if buf == nil { return fuse.ENOENT } if err := proto.Unmarshal(buf, &ref); err != nil { return fmt.Errorf("corrupt snapshot reference: %q: %v", name, err) } return nil } if err := d.fs.db.View(lookup); err != nil { return nil, err } var k cas.Key if err := k.UnmarshalBinary(ref.Key); err != nil { return nil, fmt.Errorf("corrupt snapshot reference: %q: %v", name, err) } chunk, err := d.fs.chunkStore.Get(k, "snap", 0) if err != nil { return nil, fmt.Errorf("cannot fetch snapshot: %v", err) } var snapshot wiresnap.Snapshot err = proto.Unmarshal(chunk.Buf, &snapshot) if err != nil { return nil, fmt.Errorf("corrupt snapshot: %v: %v", ref.Key, err) } n, err := snap.Open(d.fs.chunkStore, snapshot.Contents) if err != nil { return nil, fmt.Errorf("cannot serve snapshot: %v", err) } return n, nil }
// Save the local Chunk to the Store. // // On success, the old key becomes invalid. func (s *Stash) Save(key cas.Key) (cas.Key, error) { priv, ok := key.Private() if !ok { return key, nil } chunk, ok := s.local[priv] if !ok { return key, cas.NotFound{ Key: key, } } newkey, err := s.chunks.Add(chunk) if err != nil { return key, err } s.drop(priv) return newkey, nil }
// Mkdir takes a snapshot of this volume and records it under the // given name. func (d *listSnaps) Mkdir(ctx context.Context, req *fuse.MkdirRequest) (fs.Node, error) { var snapshot *wiresnap.Snapshot record := func(tx *db.Tx) error { s, err := d.fs.Snapshot(ctx, tx) if err != nil { return err } snapshot = s return nil } if err := d.fs.db.View(record); err != nil { return nil, fmt.Errorf("cannot record snapshot: %v", err) } snapshot.Name = req.Name var key cas.Key { buf, err := proto.Marshal(snapshot) if err != nil { return nil, fmt.Errorf("cannot marshal snapshot: %v", err) } if len(buf) == 0 { return nil, errors.New("marshaled snapshot become empty; this is a bug") } // store the snapshot as a chunk, for disaster recovery key, err = d.fs.chunkStore.Add(&chunks.Chunk{ Type: "snap", Level: 0, Buf: buf, }) if err != nil { return nil, fmt.Errorf("cannot store snapshot: %v", err) } } var ref = wire.SnapshotRef{ Key: key.Bytes(), } buf, err := proto.Marshal(&ref) if err != nil { return nil, fmt.Errorf("cannot marshal snapshot pointer: %v", err) } add := func(tx *db.Tx) error { b := d.fs.bucket(tx).SnapBucket() if b == nil { return errors.New("snapshot bucket missing") } return b.Put([]byte(req.Name), buf) } if err := d.fs.db.Update(add); err != nil { return nil, fmt.Errorf("cannot save snapshot pointer: %v", err) } n, err := snap.Open(d.fs.chunkStore, snapshot.Contents) if err != nil { return nil, fmt.Errorf("cannot serve snapshot: %v", err) } return n, nil }