예제 #1
0
파일: stash.go 프로젝트: jgluck/bazil
// 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
}
예제 #2
0
파일: blobs.go 프로젝트: som-snytt/bazil
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)
}
예제 #3
0
파일: stash.go 프로젝트: jgluck/bazil
// 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)
}
예제 #4
0
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

}
예제 #5
0
파일: kvchunks.go 프로젝트: jgluck/bazil
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
}
예제 #6
0
파일: to-blobs.go 프로젝트: som-snytt/bazil
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
}
예제 #7
0
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)
	}
}
예제 #8
0
파일: stash.go 프로젝트: jgluck/bazil
// 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
}
예제 #9
0
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
}
예제 #10
0
파일: stash.go 프로젝트: jgluck/bazil
// 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
}
예제 #11
0
// 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
}