github.com/containerd/Containerd@v1.4.13/snapshots/storage/metastore.go (about) 1 /* 2 Copyright The containerd Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Package storage provides a metadata storage implementation for snapshot 18 // drivers. Drive implementations are responsible for starting and managing 19 // transactions using the defined context creator. This storage package uses 20 // BoltDB for storing metadata. Access to the raw boltdb transaction is not 21 // provided, but the stored object is provided by the proto subpackage. 22 package storage 23 24 import ( 25 "context" 26 "sync" 27 28 "github.com/containerd/containerd/snapshots" 29 "github.com/pkg/errors" 30 bolt "go.etcd.io/bbolt" 31 ) 32 33 // Transactor is used to finalize an active transaction. 34 type Transactor interface { 35 // Commit commits any changes made during the transaction. On error a 36 // caller is expected to clean up any resources which would have relied 37 // on data mutated as part of this transaction. Only writable 38 // transactions can commit, non-writable must call Rollback. 39 Commit() error 40 41 // Rollback rolls back any changes made during the transaction. This 42 // must be called on all non-writable transactions and aborted writable 43 // transaction. 44 Rollback() error 45 } 46 47 // Snapshot hold the metadata for an active or view snapshot transaction. The 48 // ParentIDs hold the snapshot identifiers for the committed snapshots this 49 // active or view is based on. The ParentIDs are ordered from the lowest base 50 // to highest, meaning they should be applied in order from the first index to 51 // the last index. The last index should always be considered the active 52 // snapshots immediate parent. 53 type Snapshot struct { 54 Kind snapshots.Kind 55 ID string 56 ParentIDs []string 57 } 58 59 // MetaStore is used to store metadata related to a snapshot driver. The 60 // MetaStore is intended to store metadata related to name, state and 61 // parentage. Using the MetaStore is not required to implement a snapshot 62 // driver but can be used to handle the persistence and transactional 63 // complexities of a driver implementation. 64 type MetaStore struct { 65 dbfile string 66 67 dbL sync.Mutex 68 db *bolt.DB 69 } 70 71 // NewMetaStore returns a snapshot MetaStore for storage of metadata related to 72 // a snapshot driver backed by a bolt file database. This implementation is 73 // strongly consistent and does all metadata changes in a transaction to prevent 74 // against process crashes causing inconsistent metadata state. 75 func NewMetaStore(dbfile string) (*MetaStore, error) { 76 return &MetaStore{ 77 dbfile: dbfile, 78 }, nil 79 } 80 81 type transactionKey struct{} 82 83 // TransactionContext creates a new transaction context. The writable value 84 // should be set to true for transactions which are expected to mutate data. 85 func (ms *MetaStore) TransactionContext(ctx context.Context, writable bool) (context.Context, Transactor, error) { 86 ms.dbL.Lock() 87 if ms.db == nil { 88 db, err := bolt.Open(ms.dbfile, 0600, nil) 89 if err != nil { 90 ms.dbL.Unlock() 91 return ctx, nil, errors.Wrap(err, "failed to open database file") 92 } 93 ms.db = db 94 } 95 ms.dbL.Unlock() 96 97 tx, err := ms.db.Begin(writable) 98 if err != nil { 99 return ctx, nil, errors.Wrap(err, "failed to start transaction") 100 } 101 102 ctx = context.WithValue(ctx, transactionKey{}, tx) 103 104 return ctx, tx, nil 105 } 106 107 // Close closes the metastore and any underlying database connections 108 func (ms *MetaStore) Close() error { 109 ms.dbL.Lock() 110 defer ms.dbL.Unlock() 111 if ms.db == nil { 112 return nil 113 } 114 return ms.db.Close() 115 }