Add box to bolt

This commit is contained in:
sophia 2021-11-05 14:51:42 -05:00 committed by Paul Hinze
parent d7737effbf
commit 3e3ab869d4
No known key found for this signature in database
GPG Key ID: B69DEDF2D55501C0

View File

@ -0,0 +1,222 @@
package state
import (
"github.com/golang/protobuf/proto"
"github.com/hashicorp/go-memdb"
"github.com/hashicorp/vagrant-plugin-sdk/proto/vagrant_plugin_sdk"
"github.com/hashicorp/vagrant/internal/server/proto/vagrant_server"
bolt "go.etcd.io/bbolt"
)
var boxBucket = []byte("box")
func init() {
dbBuckets = append(dbBuckets, boxBucket)
dbIndexers = append(dbIndexers, (*State).boxIndexInit)
schemas = append(schemas, boxIndexSchema)
}
func (s *State) BoxList() ([]*vagrant_plugin_sdk.Ref_Box, error) {
memTxn := s.inmem.Txn(false)
defer memTxn.Abort()
return s.boxList(memTxn)
}
func (s *State) BoxDelete(ref *vagrant_plugin_sdk.Ref_Box) error {
memTxn := s.inmem.Txn(true)
defer memTxn.Abort()
err := s.db.Update(func(dbTxn *bolt.Tx) error {
return s.boxDelete(dbTxn, memTxn, ref)
})
if err == nil {
memTxn.Commit()
}
return err
}
func (s *State) BoxGet(ref *vagrant_plugin_sdk.Ref_Box) (*vagrant_server.Box, error) {
memTxn := s.inmem.Txn(false)
defer memTxn.Abort()
var result *vagrant_server.Box
err := s.db.View(func(dbTxn *bolt.Tx) error {
var err error
result, err = s.boxGet(dbTxn, memTxn, ref)
return err
})
return result, err
}
func (s *State) BoxtPut(box *vagrant_server.Box) error {
memTxn := s.inmem.Txn(true)
defer memTxn.Abort()
err := s.db.Update(func(dbTxn *bolt.Tx) error {
return s.boxPut(dbTxn, memTxn, box)
})
if err == nil {
memTxn.Commit()
}
return err
}
func (s *State) boxList(
memTxn *memdb.Txn,
) (r []*vagrant_plugin_sdk.Ref_Box, err error) {
iter, err := memTxn.Get(boxIndexTableName, boxIndexIdIndexName+"_prefix", "")
if err != nil {
return nil, err
}
var result []*vagrant_plugin_sdk.Ref_Box
for {
next := iter.Next()
if next == nil {
break
}
result = append(result, &vagrant_plugin_sdk.Ref_Box{
ResourceId: next.(*boxIndexRecord).Id,
Name: next.(*boxIndexRecord).Name,
Version: next.(*boxIndexRecord).Version,
Provider: next.(*boxIndexRecord).Provider,
})
}
return result, nil
}
func (s *State) boxDelete(
dbTxn *bolt.Tx,
memTxn *memdb.Txn,
ref *vagrant_plugin_sdk.Ref_Box,
) (err error) {
// TODO: should references to the box, say in the machine also be deleted?
// Delete the box
if err = dbTxn.Bucket(boxBucket).Delete(s.boxIdByRef(ref)); err != nil {
return
}
if err = memTxn.Delete(boxIndexTableName, s.newBoxIndexRecordByRef(ref)); err != nil {
return
}
return
}
func (s *State) boxGet(
dbTxn *bolt.Tx,
memTxn *memdb.Txn,
ref *vagrant_plugin_sdk.Ref_Box,
) (r *vagrant_server.Box, err error) {
var result vagrant_server.Box
b := dbTxn.Bucket(boxBucket)
return &result, dbGet(b, s.boxIdByRef(ref), &result)
}
func (s *State) boxPut(
dbTxn *bolt.Tx,
memTxn *memdb.Txn,
value *vagrant_server.Box,
) (err error) {
id := s.boxId(value)
b := dbTxn.Bucket(boxBucket)
if err = dbPut(b, id, value); err != nil {
s.log.Error("failed to store box in db", "box", value, "error", err)
return
}
s.log.Trace("indexing box", "box", value)
if err = s.boxIndexSet(memTxn, id, value); err != nil {
s.log.Error("failed to index box", "box", value, "error", err)
return
}
return
}
const (
boxIndexIdIndexName = "id"
boxIndexNameIndexName = "name"
boxIndexTableName = "box-index"
)
type boxIndexRecord struct {
Id string // Resource ID
Name string // Box Name
Version string // Box Version
Provider string // Box Provider
}
func (s *State) newBoxIndexRecord(b *vagrant_server.Box) *boxIndexRecord {
id := b.Name + "-" + b.Version + "-" + b.Provider
return &boxIndexRecord{
Id: id,
Name: b.Name,
Version: b.Version,
Provider: b.Provider,
}
}
func (s *State) boxIndexSet(txn *memdb.Txn, id []byte, value *vagrant_server.Box) error {
return txn.Insert(boxIndexTableName, s.newBoxIndexRecord(value))
}
func (s *State) boxIndexInit(dbTxn *bolt.Tx, memTxn *memdb.Txn) error {
bucket := dbTxn.Bucket(boxBucket)
return bucket.ForEach(func(k, v []byte) error {
var value vagrant_server.Box
if err := proto.Unmarshal(v, &value); err != nil {
return err
}
if err := s.boxIndexSet(memTxn, k, &value); err != nil {
return err
}
return nil
})
}
func boxIndexSchema() *memdb.TableSchema {
return &memdb.TableSchema{
Name: boxIndexTableName,
Indexes: map[string]*memdb.IndexSchema{
boxIndexIdIndexName: {
Name: boxIndexIdIndexName,
AllowMissing: false,
Unique: true,
Indexer: &memdb.StringFieldIndex{
Field: "Id",
Lowercase: true,
},
},
boxIndexNameIndexName: {
Name: boxIndexNameIndexName,
AllowMissing: false,
Unique: false,
Indexer: &memdb.StringFieldIndex{
Field: "Name",
Lowercase: true,
},
},
},
}
}
func (s *State) newBoxIndexRecordByRef(ref *vagrant_plugin_sdk.Ref_Box) *boxIndexRecord {
return &boxIndexRecord{
Id: ref.ResourceId,
Name: ref.Name,
Version: ref.Version,
Provider: ref.Provider,
}
}
func (s *State) boxId(b *vagrant_server.Box) []byte {
return []byte(b.Id)
}
func (s *State) boxIdByRef(b *vagrant_plugin_sdk.Ref_Box) []byte {
return []byte(b.ResourceId)
}