github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/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  }