github.com/adnan-c/fabric_e2e_couchdb@v0.6.1-preview.0.20170228180935-21ce6b23cf91/core/ledger/kvledger/kv_ledger_provider.go (about) 1 /* 2 Copyright IBM Corp. 2016 All Rights Reserved. 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 kvledger 18 19 import ( 20 "errors" 21 22 "github.com/hyperledger/fabric/common/ledger/blkstorage" 23 "github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage" 24 "github.com/hyperledger/fabric/common/ledger/util/leveldbhelper" 25 "github.com/hyperledger/fabric/core/ledger" 26 "github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb" 27 "github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb/historyleveldb" 28 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb" 29 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb/statecouchdb" 30 "github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb/stateleveldb" 31 "github.com/hyperledger/fabric/core/ledger/ledgerconfig" 32 ) 33 34 var ( 35 // ErrLedgerIDExists is thrown by a CreateLedger call if a ledger with the given id already exists 36 ErrLedgerIDExists = errors.New("LedgerID already exists") 37 // ErrNonExistingLedgerID is thrown by a OpenLedger call if a ledger with the given id does not exist 38 ErrNonExistingLedgerID = errors.New("LedgerID does not exist") 39 // ErrLedgerNotOpened is thrown by a CloseLedger call if a ledger with the given id has not been opened 40 ErrLedgerNotOpened = errors.New("Ledger is not opened yet") 41 ) 42 43 // Provider implements interface ledger.PeerLedgerProvider 44 type Provider struct { 45 idStore *idStore 46 blockStoreProvider blkstorage.BlockStoreProvider 47 vdbProvider statedb.VersionedDBProvider 48 historydbProvider historydb.HistoryDBProvider 49 } 50 51 // NewProvider instantiates a new Provider. 52 // This is not thread-safe and assumed to be synchronized be the caller 53 func NewProvider() (ledger.PeerLedgerProvider, error) { 54 55 logger.Info("Initializing ledger provider") 56 57 // Initialize the ID store (inventory of chainIds/ledgerIds) 58 idStore := openIDStore(ledgerconfig.GetLedgerProviderPath()) 59 60 // Initialize the block storage 61 attrsToIndex := []blkstorage.IndexableAttr{ 62 blkstorage.IndexableAttrBlockHash, 63 blkstorage.IndexableAttrBlockNum, 64 blkstorage.IndexableAttrTxID, 65 blkstorage.IndexableAttrBlockNumTranNum, 66 blkstorage.IndexableAttrBlockTxID, 67 blkstorage.IndexableAttrTxValidationCode, 68 } 69 indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex} 70 blockStoreProvider := fsblkstorage.NewProvider( 71 fsblkstorage.NewConf(ledgerconfig.GetBlockStorePath(), ledgerconfig.GetMaxBlockfileSize()), 72 indexConfig) 73 74 // Initialize the versioned database (state database) 75 var vdbProvider statedb.VersionedDBProvider 76 if !ledgerconfig.IsCouchDBEnabled() { 77 logger.Debug("Constructing leveldb VersionedDBProvider") 78 vdbProvider = stateleveldb.NewVersionedDBProvider() 79 } else { 80 logger.Debug("Constructing CouchDB VersionedDBProvider") 81 var err error 82 vdbProvider, err = statecouchdb.NewVersionedDBProvider() 83 if err != nil { 84 return nil, err 85 } 86 } 87 88 // Initialize the history database (index for history of values by key) 89 var historydbProvider historydb.HistoryDBProvider 90 historydbProvider = historyleveldb.NewHistoryDBProvider() 91 92 logger.Info("ledger provider Initialized") 93 return &Provider{idStore, blockStoreProvider, vdbProvider, historydbProvider}, nil 94 } 95 96 // Create implements the corresponding method from interface ledger.PeerLedgerProvider 97 func (provider *Provider) Create(ledgerID string) (ledger.PeerLedger, error) { 98 exists, err := provider.idStore.ledgerIDExists(ledgerID) 99 if err != nil { 100 return nil, err 101 } 102 if exists { 103 return nil, ErrLedgerIDExists 104 } 105 provider.idStore.createLedgerID(ledgerID) 106 return provider.Open(ledgerID) 107 } 108 109 // Open implements the corresponding method from interface ledger.PeerLedgerProvider 110 func (provider *Provider) Open(ledgerID string) (ledger.PeerLedger, error) { 111 112 logger.Debugf("Open() opening kvledger: %s", ledgerID) 113 114 // Check the ID store to ensure that the chainId/ledgerId exists 115 exists, err := provider.idStore.ledgerIDExists(ledgerID) 116 if err != nil { 117 return nil, err 118 } 119 if !exists { 120 return nil, ErrNonExistingLedgerID 121 } 122 123 // Get the block store for a chain/ledger 124 blockStore, err := provider.blockStoreProvider.OpenBlockStore(ledgerID) 125 if err != nil { 126 return nil, err 127 } 128 129 // Get the versioned database (state database) for a chain/ledger 130 vDB, err := provider.vdbProvider.GetDBHandle(ledgerID) 131 if err != nil { 132 return nil, err 133 } 134 135 // Get the history database (index for history of values by key) for a chain/ledger 136 historyDB, err := provider.historydbProvider.GetDBHandle(ledgerID) 137 if err != nil { 138 return nil, err 139 } 140 141 // Create a kvLedger for this chain/ledger, which encasulates the underlying data stores 142 // (id store, blockstore, state database, history database) 143 l, err := newKVLedger(ledgerID, blockStore, vDB, historyDB) 144 if err != nil { 145 return nil, err 146 } 147 return l, nil 148 } 149 150 // Exists implements the corresponding method from interface ledger.PeerLedgerProvider 151 func (provider *Provider) Exists(ledgerID string) (bool, error) { 152 return provider.idStore.ledgerIDExists(ledgerID) 153 } 154 155 // List implements the corresponding method from interface ledger.PeerLedgerProvider 156 func (provider *Provider) List() ([]string, error) { 157 return provider.idStore.getAllLedgerIds() 158 } 159 160 // Close implements the corresponding method from interface ledger.PeerLedgerProvider 161 func (provider *Provider) Close() { 162 provider.idStore.close() 163 provider.blockStoreProvider.Close() 164 provider.vdbProvider.Close() 165 provider.historydbProvider.Close() 166 } 167 168 type idStore struct { 169 db *leveldbhelper.DB 170 } 171 172 func openIDStore(path string) *idStore { 173 db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: path}) 174 db.Open() 175 return &idStore{db} 176 } 177 178 func (s *idStore) createLedgerID(ledgerID string) error { 179 key := []byte(ledgerID) 180 val := []byte{} 181 err := error(nil) 182 if val, err = s.db.Get(key); err != nil { 183 return err 184 } 185 if val != nil { 186 return ErrLedgerIDExists 187 } 188 return s.db.Put(key, val, true) 189 } 190 191 func (s *idStore) ledgerIDExists(ledgerID string) (bool, error) { 192 key := []byte(ledgerID) 193 val := []byte{} 194 err := error(nil) 195 if val, err = s.db.Get(key); err != nil { 196 return false, err 197 } 198 return val != nil, nil 199 } 200 201 func (s *idStore) getAllLedgerIds() ([]string, error) { 202 var ids []string 203 itr := s.db.GetIterator(nil, nil) 204 itr.First() 205 for itr.Valid() { 206 key := string(itr.Key()) 207 ids = append(ids, key) 208 itr.Next() 209 } 210 return ids, nil 211 } 212 213 func (s *idStore) close() { 214 s.db.Close() 215 }