|
|
|
|
@@ -77,27 +77,6 @@ type nameAssociation struct {
|
|
|
|
|
containerID string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ViewDB provides an in-memory transactional (ACID) container Store
|
|
|
|
|
type ViewDB interface {
|
|
|
|
|
Snapshot() View
|
|
|
|
|
Save(*Container) error
|
|
|
|
|
Delete(*Container) error
|
|
|
|
|
|
|
|
|
|
GetByPrefix(string) (string, error)
|
|
|
|
|
|
|
|
|
|
ReserveName(name, containerID string) error
|
|
|
|
|
ReleaseName(name string) error
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// View can be used by readers to avoid locking
|
|
|
|
|
type View interface {
|
|
|
|
|
All() ([]Snapshot, error)
|
|
|
|
|
Get(id string) (*Snapshot, error)
|
|
|
|
|
|
|
|
|
|
GetID(name string) (string, error)
|
|
|
|
|
GetAllNames() map[string][]string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var schema = &memdb.DBSchema{
|
|
|
|
|
Tables: map[string]*memdb.TableSchema{
|
|
|
|
|
memdbContainersTable: {
|
|
|
|
|
@@ -128,7 +107,8 @@ var schema = &memdb.DBSchema{
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type memDB struct {
|
|
|
|
|
// ViewDB provides an in-memory transactional (ACID) container store.
|
|
|
|
|
type ViewDB struct {
|
|
|
|
|
store *memdb.MemDB
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -144,15 +124,17 @@ func (e NoSuchContainerError) Error() string {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// NewViewDB provides the default implementation, with the default schema
|
|
|
|
|
func NewViewDB() (ViewDB, error) {
|
|
|
|
|
func NewViewDB() (*ViewDB, error) {
|
|
|
|
|
store, err := memdb.NewMemDB(schema)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
return &memDB{store: store}, nil
|
|
|
|
|
return &ViewDB{store: store}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (db *memDB) GetByPrefix(s string) (string, error) {
|
|
|
|
|
// GetByPrefix returns a container with the given ID prefix. It returns an
|
|
|
|
|
// error if an empty prefix was given or if multiple containers match the prefix.
|
|
|
|
|
func (db *ViewDB) GetByPrefix(s string) (string, error) {
|
|
|
|
|
if s == "" {
|
|
|
|
|
return "", ErrEmptyPrefix
|
|
|
|
|
}
|
|
|
|
|
@@ -184,14 +166,14 @@ func (db *memDB) GetByPrefix(s string) (string, error) {
|
|
|
|
|
return "", ErrNotExist
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Snapshot provides a consistent read-only View of the database
|
|
|
|
|
func (db *memDB) Snapshot() View {
|
|
|
|
|
return &memdbView{
|
|
|
|
|
// Snapshot provides a consistent read-only view of the database.
|
|
|
|
|
func (db *ViewDB) Snapshot() *View {
|
|
|
|
|
return &View{
|
|
|
|
|
txn: db.store.Txn(false),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (db *memDB) withTxn(cb func(*memdb.Txn) error) error {
|
|
|
|
|
func (db *ViewDB) withTxn(cb func(*memdb.Txn) error) error {
|
|
|
|
|
txn := db.store.Txn(true)
|
|
|
|
|
err := cb(txn)
|
|
|
|
|
if err != nil {
|
|
|
|
|
@@ -204,16 +186,16 @@ func (db *memDB) withTxn(cb func(*memdb.Txn) error) error {
|
|
|
|
|
|
|
|
|
|
// Save atomically updates the in-memory store state for a Container.
|
|
|
|
|
// Only read only (deep) copies of containers may be passed in.
|
|
|
|
|
func (db *memDB) Save(c *Container) error {
|
|
|
|
|
func (db *ViewDB) Save(c *Container) error {
|
|
|
|
|
return db.withTxn(func(txn *memdb.Txn) error {
|
|
|
|
|
return txn.Insert(memdbContainersTable, c)
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Delete removes an item by ID
|
|
|
|
|
func (db *memDB) Delete(c *Container) error {
|
|
|
|
|
func (db *ViewDB) Delete(c *Container) error {
|
|
|
|
|
return db.withTxn(func(txn *memdb.Txn) error {
|
|
|
|
|
view := &memdbView{txn: txn}
|
|
|
|
|
view := &View{txn: txn}
|
|
|
|
|
names := view.getNames(c.ID)
|
|
|
|
|
|
|
|
|
|
for _, name := range names {
|
|
|
|
|
@@ -231,7 +213,7 @@ func (db *memDB) Delete(c *Container) error {
|
|
|
|
|
// ReserveName is idempotent
|
|
|
|
|
// Attempting to reserve a container ID to a name that already exists results in an `ErrNameReserved`
|
|
|
|
|
// A name reservation is globally unique
|
|
|
|
|
func (db *memDB) ReserveName(name, containerID string) error {
|
|
|
|
|
func (db *ViewDB) ReserveName(name, containerID string) error {
|
|
|
|
|
return db.withTxn(func(txn *memdb.Txn) error {
|
|
|
|
|
s, err := txn.First(memdbNamesTable, memdbIDIndex, name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
@@ -249,18 +231,19 @@ func (db *memDB) ReserveName(name, containerID string) error {
|
|
|
|
|
|
|
|
|
|
// ReleaseName releases the reserved name
|
|
|
|
|
// Once released, a name can be reserved again
|
|
|
|
|
func (db *memDB) ReleaseName(name string) error {
|
|
|
|
|
func (db *ViewDB) ReleaseName(name string) error {
|
|
|
|
|
return db.withTxn(func(txn *memdb.Txn) error {
|
|
|
|
|
return txn.Delete(memdbNamesTable, nameAssociation{name: name})
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type memdbView struct {
|
|
|
|
|
// View provides a consistent read-only view of the database.
|
|
|
|
|
type View struct {
|
|
|
|
|
txn *memdb.Txn
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// All returns a all items in this snapshot. Returned objects must never be modified.
|
|
|
|
|
func (v *memdbView) All() ([]Snapshot, error) {
|
|
|
|
|
func (v *View) All() ([]Snapshot, error) {
|
|
|
|
|
var all []Snapshot
|
|
|
|
|
iter, err := v.txn.Get(memdbContainersTable, memdbIDIndex)
|
|
|
|
|
if err != nil {
|
|
|
|
|
@@ -278,7 +261,7 @@ func (v *memdbView) All() ([]Snapshot, error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Get returns an item by id. Returned objects must never be modified.
|
|
|
|
|
func (v *memdbView) Get(id string) (*Snapshot, error) {
|
|
|
|
|
func (v *View) Get(id string) (*Snapshot, error) {
|
|
|
|
|
s, err := v.txn.First(memdbContainersTable, memdbIDIndex, id)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
@@ -290,7 +273,7 @@ func (v *memdbView) Get(id string) (*Snapshot, error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// getNames lists all the reserved names for the given container ID.
|
|
|
|
|
func (v *memdbView) getNames(containerID string) []string {
|
|
|
|
|
func (v *View) getNames(containerID string) []string {
|
|
|
|
|
iter, err := v.txn.Get(memdbNamesTable, memdbContainerIDIndex, containerID)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil
|
|
|
|
|
@@ -309,7 +292,7 @@ func (v *memdbView) getNames(containerID string) []string {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetID returns the container ID that the passed in name is reserved to.
|
|
|
|
|
func (v *memdbView) GetID(name string) (string, error) {
|
|
|
|
|
func (v *View) GetID(name string) (string, error) {
|
|
|
|
|
s, err := v.txn.First(memdbNamesTable, memdbIDIndex, name)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return "", err
|
|
|
|
|
@@ -321,7 +304,7 @@ func (v *memdbView) GetID(name string) (string, error) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetAllNames returns all registered names.
|
|
|
|
|
func (v *memdbView) GetAllNames() map[string][]string {
|
|
|
|
|
func (v *View) GetAllNames() map[string][]string {
|
|
|
|
|
iter, err := v.txn.Get(memdbNamesTable, memdbContainerIDIndex)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil
|
|
|
|
|
@@ -342,7 +325,7 @@ func (v *memdbView) GetAllNames() map[string][]string {
|
|
|
|
|
|
|
|
|
|
// transform maps a (deep) copied Container object to what queries need.
|
|
|
|
|
// A lock on the Container is not held because these are immutable deep copies.
|
|
|
|
|
func (v *memdbView) transform(container *Container) *Snapshot {
|
|
|
|
|
func (v *View) transform(container *Container) *Snapshot {
|
|
|
|
|
health := types.NoHealthcheck
|
|
|
|
|
if container.Health != nil {
|
|
|
|
|
health = container.Health.Status()
|
|
|
|
|
|