github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/kvledger/kv_ledger_provider.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package kvledger 8 9 import ( 10 "bytes" 11 "fmt" 12 "os" 13 "path" 14 15 "github.com/golang/protobuf/proto" 16 "github.com/hyperledger/fabric-protos-go/common" 17 "github.com/osdi23p228/fabric/common/ledger/blkstorage" 18 "github.com/osdi23p228/fabric/common/ledger/dataformat" 19 "github.com/osdi23p228/fabric/common/ledger/util/leveldbhelper" 20 "github.com/osdi23p228/fabric/core/ledger" 21 "github.com/osdi23p228/fabric/core/ledger/confighistory" 22 "github.com/osdi23p228/fabric/core/ledger/kvledger/bookkeeping" 23 "github.com/osdi23p228/fabric/core/ledger/kvledger/history" 24 "github.com/osdi23p228/fabric/core/ledger/kvledger/msgs" 25 "github.com/osdi23p228/fabric/core/ledger/kvledger/txmgmt/privacyenabledstate" 26 "github.com/osdi23p228/fabric/core/ledger/pvtdatastorage" 27 "github.com/osdi23p228/fabric/protoutil" 28 "github.com/pkg/errors" 29 "github.com/syndtr/goleveldb/leveldb" 30 ) 31 32 var ( 33 // ErrLedgerIDExists is thrown by a CreateLedger call if a ledger with the given id already exists 34 ErrLedgerIDExists = errors.New("LedgerID already exists") 35 // ErrNonExistingLedgerID is thrown by an OpenLedger call if a ledger with the given id does not exist 36 ErrNonExistingLedgerID = errors.New("LedgerID does not exist") 37 // ErrLedgerNotOpened is thrown by a CloseLedger call if a ledger with the given id has not been opened 38 ErrLedgerNotOpened = errors.New("ledger is not opened yet") 39 // ErrInactiveLedger is thrown by an OpenLedger call if a ledger with the given id is not active 40 ErrInactiveLedger = errors.New("Ledger is not active") 41 42 underConstructionLedgerKey = []byte("underConstructionLedgerKey") 43 // ledgerKeyPrefix is the prefix for each ledger key in idStore db 44 ledgerKeyPrefix = []byte{'l'} 45 // ledgerKeyStop is the end key when querying idStore db by ledger key 46 ledgerKeyStop = []byte{'l' + 1} 47 // metadataKeyPrefix is the prefix for each metadata key in idStore db 48 metadataKeyPrefix = []byte{'s'} 49 // metadataKeyStop is the end key when querying idStore db by metadata key 50 metadataKeyStop = []byte{'s' + 1} 51 52 // formatKey 53 formatKey = []byte("f") 54 55 attrsToIndex = []blkstorage.IndexableAttr{ 56 blkstorage.IndexableAttrBlockHash, 57 blkstorage.IndexableAttrBlockNum, 58 blkstorage.IndexableAttrTxID, 59 blkstorage.IndexableAttrBlockNumTranNum, 60 } 61 ) 62 63 const maxBlockFileSize = 64 * 1024 * 1024 64 65 // Provider implements interface ledger.PeerLedgerProvider 66 type Provider struct { 67 idStore *idStore 68 blkStoreProvider *blkstorage.BlockStoreProvider 69 pvtdataStoreProvider *pvtdatastorage.Provider 70 dbProvider *privacyenabledstate.DBProvider 71 historydbProvider *history.DBProvider 72 configHistoryMgr *confighistory.Mgr 73 stateListeners []ledger.StateListener 74 bookkeepingProvider bookkeeping.Provider 75 initializer *ledger.Initializer 76 collElgNotifier *collElgNotifier 77 stats *stats 78 fileLock *leveldbhelper.FileLock 79 } 80 81 // NewProvider instantiates a new Provider. 82 // This is not thread-safe and assumed to be synchronized by the caller 83 func NewProvider(initializer *ledger.Initializer) (pr *Provider, e error) { 84 p := &Provider{ 85 initializer: initializer, 86 } 87 88 defer func() { 89 if e != nil { 90 p.Close() 91 if errFormatMismatch, ok := e.(*dataformat.ErrFormatMismatch); ok { 92 if errFormatMismatch.Format == dataformat.PreviousFormat && errFormatMismatch.ExpectedFormat == dataformat.CurrentFormat { 93 logger.Errorf("Please execute the 'peer node upgrade-dbs' command to upgrade the database format: %s", errFormatMismatch) 94 } else { 95 logger.Errorf("Please check the Fabric version matches the ledger data format: %s", errFormatMismatch) 96 } 97 } 98 } 99 }() 100 101 fileLockPath := fileLockPath(initializer.Config.RootFSPath) 102 fileLock := leveldbhelper.NewFileLock(fileLockPath) 103 if err := fileLock.Lock(); err != nil { 104 return nil, errors.Wrap(err, "as another peer node command is executing,"+ 105 " wait for that command to complete its execution or terminate it before retrying") 106 } 107 108 p.fileLock = fileLock 109 110 if err := p.initLedgerIDInventory(); err != nil { 111 return nil, err 112 } 113 if err := p.initBlockStoreProvider(); err != nil { 114 return nil, err 115 } 116 if err := p.initPvtDataStoreProvider(); err != nil { 117 return nil, err 118 } 119 if err := p.initHistoryDBProvider(); err != nil { 120 return nil, err 121 } 122 if err := p.initConfigHistoryManager(); err != nil { 123 return nil, err 124 } 125 p.initCollElgNotifier() 126 p.initStateListeners() 127 if err := p.initStateDBProvider(); err != nil { 128 return nil, err 129 } 130 p.initLedgerStatistics() 131 p.recoverUnderConstructionLedger() 132 if err := p.initSnapshotDir(); err != nil { 133 return nil, err 134 } 135 return p, nil 136 } 137 138 func (p *Provider) initLedgerIDInventory() error { 139 idStore, err := openIDStore(LedgerProviderPath(p.initializer.Config.RootFSPath)) 140 if err != nil { 141 return err 142 } 143 p.idStore = idStore 144 return nil 145 } 146 147 func (p *Provider) initBlockStoreProvider() error { 148 indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex} 149 blkStoreProvider, err := blkstorage.NewProvider( 150 blkstorage.NewConf( 151 BlockStorePath(p.initializer.Config.RootFSPath), 152 maxBlockFileSize, 153 ), 154 indexConfig, 155 p.initializer.MetricsProvider, 156 ) 157 if err != nil { 158 return err 159 } 160 p.blkStoreProvider = blkStoreProvider 161 return nil 162 } 163 164 func (p *Provider) initPvtDataStoreProvider() error { 165 privateDataConfig := &pvtdatastorage.PrivateDataConfig{ 166 PrivateDataConfig: p.initializer.Config.PrivateDataConfig, 167 StorePath: PvtDataStorePath(p.initializer.Config.RootFSPath), 168 } 169 pvtdataStoreProvider, err := pvtdatastorage.NewProvider(privateDataConfig) 170 if err != nil { 171 return err 172 } 173 p.pvtdataStoreProvider = pvtdataStoreProvider 174 return nil 175 } 176 177 func (p *Provider) initHistoryDBProvider() error { 178 if !p.initializer.Config.HistoryDBConfig.Enabled { 179 return nil 180 } 181 // Initialize the history database (index for history of values by key) 182 historydbProvider, err := history.NewDBProvider( 183 HistoryDBPath(p.initializer.Config.RootFSPath), 184 ) 185 if err != nil { 186 return err 187 } 188 p.historydbProvider = historydbProvider 189 return nil 190 } 191 192 func (p *Provider) initConfigHistoryManager() error { 193 var err error 194 configHistoryMgr, err := confighistory.NewMgr( 195 ConfigHistoryDBPath(p.initializer.Config.RootFSPath), 196 p.initializer.DeployedChaincodeInfoProvider, 197 ) 198 if err != nil { 199 return err 200 } 201 p.configHistoryMgr = configHistoryMgr 202 return nil 203 } 204 205 func (p *Provider) initCollElgNotifier() { 206 collElgNotifier := &collElgNotifier{ 207 p.initializer.DeployedChaincodeInfoProvider, 208 p.initializer.MembershipInfoProvider, 209 make(map[string]collElgListener), 210 } 211 p.collElgNotifier = collElgNotifier 212 } 213 214 func (p *Provider) initStateListeners() { 215 stateListeners := p.initializer.StateListeners 216 stateListeners = append(stateListeners, p.collElgNotifier) 217 stateListeners = append(stateListeners, p.configHistoryMgr) 218 p.stateListeners = stateListeners 219 } 220 221 func (p *Provider) initStateDBProvider() error { 222 var err error 223 p.bookkeepingProvider, err = bookkeeping.NewProvider( 224 BookkeeperDBPath(p.initializer.Config.RootFSPath), 225 ) 226 if err != nil { 227 return err 228 } 229 stateDB := &privacyenabledstate.StateDBConfig{ 230 StateDBConfig: p.initializer.Config.StateDBConfig, 231 LevelDBPath: StateDBPath(p.initializer.Config.RootFSPath), 232 } 233 sysNamespaces := p.initializer.DeployedChaincodeInfoProvider.Namespaces() 234 p.dbProvider, err = privacyenabledstate.NewDBProvider( 235 p.bookkeepingProvider, 236 p.initializer.MetricsProvider, 237 p.initializer.HealthCheckRegistry, 238 stateDB, 239 sysNamespaces, 240 ) 241 return err 242 } 243 244 func (p *Provider) initLedgerStatistics() { 245 p.stats = newStats(p.initializer.MetricsProvider) 246 } 247 248 func (p *Provider) initSnapshotDir() error { 249 snapshotsRootDir := p.initializer.Config.SnapshotsConfig.RootDir 250 if !path.IsAbs(snapshotsRootDir) { 251 return errors.Errorf("invalid path: %s. The path for the snapshot dir is expected to be an absolute path", snapshotsRootDir) 252 } 253 254 inProgressSnapshotsPath := InProgressSnapshotsPath(snapshotsRootDir) 255 completedSnapshotsPath := CompletedSnapshotsPath(snapshotsRootDir) 256 257 if err := os.RemoveAll(inProgressSnapshotsPath); err != nil { 258 return errors.Wrapf(err, "error while deleting the dir: %s", inProgressSnapshotsPath) 259 } 260 if err := os.MkdirAll(inProgressSnapshotsPath, 0755); err != nil { 261 return errors.Wrapf(err, "error while creating the dir: %s", inProgressSnapshotsPath) 262 } 263 if err := os.MkdirAll(completedSnapshotsPath, 0755); err != nil { 264 return errors.Wrapf(err, "error while creating the dir: %s", completedSnapshotsPath) 265 } 266 return syncDir(snapshotsRootDir) 267 } 268 269 // Create implements the corresponding method from interface ledger.PeerLedgerProvider 270 // This functions sets a under construction flag before doing any thing related to ledger creation and 271 // upon a successful ledger creation with the committed genesis block, removes the flag and add entry into 272 // created ledgers list (atomically). If a crash happens in between, the 'recoverUnderConstructionLedger' 273 // function is invoked before declaring the provider to be usable 274 func (p *Provider) Create(genesisBlock *common.Block) (ledger.PeerLedger, error) { 275 ledgerID, err := protoutil.GetChannelIDFromBlock(genesisBlock) 276 if err != nil { 277 return nil, err 278 } 279 exists, err := p.idStore.ledgerIDExists(ledgerID) 280 if err != nil { 281 return nil, err 282 } 283 if exists { 284 return nil, ErrLedgerIDExists 285 } 286 if err = p.idStore.setUnderConstructionFlag(ledgerID); err != nil { 287 return nil, err 288 } 289 lgr, err := p.open(ledgerID) 290 if err != nil { 291 logger.Errorf("Error opening a new empty ledger. Unsetting under construction flag. Error: %+v", err) 292 panicOnErr(p.runCleanup(ledgerID), "Error running cleanup for ledger id [%s]", ledgerID) 293 panicOnErr(p.idStore.unsetUnderConstructionFlag(), "Error while unsetting under construction flag") 294 return nil, err 295 } 296 if err := lgr.CommitLegacy(&ledger.BlockAndPvtData{Block: genesisBlock}, &ledger.CommitOptions{}); err != nil { 297 lgr.Close() 298 return nil, err 299 } 300 panicOnErr(p.idStore.createLedgerID(ledgerID, genesisBlock), "Error while marking ledger as created") 301 return lgr, nil 302 } 303 304 // Open implements the corresponding method from interface ledger.PeerLedgerProvider 305 func (p *Provider) Open(ledgerID string) (ledger.PeerLedger, error) { 306 logger.Debugf("Open() opening kvledger: %s", ledgerID) 307 // Check the ID store to ensure that the chainId/ledgerId exists 308 active, exists, err := p.idStore.ledgerIDActive(ledgerID) 309 if err != nil { 310 return nil, err 311 } 312 if !exists { 313 return nil, ErrNonExistingLedgerID 314 } 315 if !active { 316 return nil, ErrInactiveLedger 317 } 318 return p.open(ledgerID) 319 } 320 321 func (p *Provider) open(ledgerID string) (ledger.PeerLedger, error) { 322 // Get the block store for a chain/ledger 323 blockStore, err := p.blkStoreProvider.Open(ledgerID) 324 if err != nil { 325 return nil, err 326 } 327 328 pvtdataStore, err := p.pvtdataStoreProvider.OpenStore(ledgerID) 329 if err != nil { 330 return nil, err 331 } 332 333 p.collElgNotifier.registerListener(ledgerID, pvtdataStore) 334 335 // Get the versioned database (state database) for a chain/ledger 336 channelInfoProvider := &channelInfoProvider{ledgerID, blockStore, p.collElgNotifier.deployedChaincodeInfoProvider} 337 db, err := p.dbProvider.GetDBHandle(ledgerID, channelInfoProvider) 338 if err != nil { 339 return nil, err 340 } 341 342 // Get the history database (index for history of values by key) for a chain/ledger 343 var historyDB *history.DB 344 if p.historydbProvider != nil { 345 historyDB, err = p.historydbProvider.GetDBHandle(ledgerID) 346 if err != nil { 347 return nil, err 348 } 349 } 350 351 initializer := &lgrInitializer{ 352 ledgerID: ledgerID, 353 blockStore: blockStore, 354 pvtdataStore: pvtdataStore, 355 stateDB: db, 356 historyDB: historyDB, 357 configHistoryMgr: p.configHistoryMgr, 358 stateListeners: p.stateListeners, 359 bookkeeperProvider: p.bookkeepingProvider, 360 ccInfoProvider: p.initializer.DeployedChaincodeInfoProvider, 361 ccLifecycleEventProvider: p.initializer.ChaincodeLifecycleEventProvider, 362 stats: p.stats.ledgerStats(ledgerID), 363 customTxProcessors: p.initializer.CustomTxProcessors, 364 hashProvider: p.initializer.HashProvider, 365 snapshotsConfig: p.initializer.Config.SnapshotsConfig, 366 } 367 368 l, err := newKVLedger(initializer) 369 if err != nil { 370 return nil, err 371 } 372 return l, nil 373 } 374 375 // Exists implements the corresponding method from interface ledger.PeerLedgerProvider 376 func (p *Provider) Exists(ledgerID string) (bool, error) { 377 return p.idStore.ledgerIDExists(ledgerID) 378 } 379 380 // List implements the corresponding method from interface ledger.PeerLedgerProvider 381 func (p *Provider) List() ([]string, error) { 382 return p.idStore.getActiveLedgerIDs() 383 } 384 385 // Close implements the corresponding method from interface ledger.PeerLedgerProvider 386 func (p *Provider) Close() { 387 if p.idStore != nil { 388 p.idStore.close() 389 } 390 if p.blkStoreProvider != nil { 391 p.blkStoreProvider.Close() 392 } 393 if p.pvtdataStoreProvider != nil { 394 p.pvtdataStoreProvider.Close() 395 } 396 if p.dbProvider != nil { 397 p.dbProvider.Close() 398 } 399 if p.bookkeepingProvider != nil { 400 p.bookkeepingProvider.Close() 401 } 402 if p.configHistoryMgr != nil { 403 p.configHistoryMgr.Close() 404 } 405 if p.historydbProvider != nil { 406 p.historydbProvider.Close() 407 } 408 if p.fileLock != nil { 409 p.fileLock.Unlock() 410 } 411 } 412 413 // recoverUnderConstructionLedger checks whether the under construction flag is set - this would be the case 414 // if a crash had happened during creation of ledger and the ledger creation could have been left in intermediate 415 // state. Recovery checks if the ledger was created and the genesis block was committed successfully then it completes 416 // the last step of adding the ledger id to the list of created ledgers. Else, it clears the under construction flag 417 func (p *Provider) recoverUnderConstructionLedger() { 418 logger.Debugf("Recovering under construction ledger") 419 ledgerID, err := p.idStore.getUnderConstructionFlag() 420 panicOnErr(err, "Error while checking whether the under construction flag is set") 421 if ledgerID == "" { 422 logger.Debugf("No under construction ledger found. Quitting recovery") 423 return 424 } 425 logger.Infof("ledger [%s] found as under construction", ledgerID) 426 ledger, err := p.open(ledgerID) 427 panicOnErr(err, "Error while opening under construction ledger [%s]", ledgerID) 428 bcInfo, err := ledger.GetBlockchainInfo() 429 panicOnErr(err, "Error while getting blockchain info for the under construction ledger [%s]", ledgerID) 430 ledger.Close() 431 432 switch bcInfo.Height { 433 case 0: 434 logger.Infof("Genesis block was not committed. Hence, the peer ledger not created. unsetting the under construction flag") 435 panicOnErr(p.runCleanup(ledgerID), "Error while running cleanup for ledger id [%s]", ledgerID) 436 panicOnErr(p.idStore.unsetUnderConstructionFlag(), "Error while unsetting under construction flag") 437 case 1: 438 logger.Infof("Genesis block was committed. Hence, marking the peer ledger as created") 439 genesisBlock, err := ledger.GetBlockByNumber(0) 440 panicOnErr(err, "Error while retrieving genesis block from blockchain for ledger [%s]", ledgerID) 441 panicOnErr(p.idStore.createLedgerID(ledgerID, genesisBlock), "Error while adding ledgerID [%s] to created list", ledgerID) 442 default: 443 panic(errors.Errorf( 444 "data inconsistency: under construction flag is set for ledger [%s] while the height of the blockchain is [%d]", 445 ledgerID, bcInfo.Height)) 446 } 447 } 448 449 // runCleanup cleans up blockstorage, statedb, and historydb for what 450 // may have got created during in-complete ledger creation 451 func (p *Provider) runCleanup(ledgerID string) error { 452 // TODO - though, not having this is harmless for kv ledger. 453 // If we want, following could be done: 454 // - blockstorage could remove empty folders 455 // - couchdb backed statedb could delete the database if got created 456 // - leveldb backed statedb and history db need not perform anything as it uses a single db shared across ledgers 457 return nil 458 } 459 460 func panicOnErr(err error, mgsFormat string, args ...interface{}) { 461 if err == nil { 462 return 463 } 464 args = append(args, err) 465 panic(fmt.Sprintf(mgsFormat+" Error: %s", args...)) 466 } 467 468 ////////////////////////////////////////////////////////////////////// 469 // Ledger id persistence related code 470 /////////////////////////////////////////////////////////////////////// 471 type idStore struct { 472 db *leveldbhelper.DB 473 dbPath string 474 } 475 476 func openIDStore(path string) (s *idStore, e error) { 477 db := leveldbhelper.CreateDB(&leveldbhelper.Conf{DBPath: path}) 478 db.Open() 479 defer func() { 480 if e != nil { 481 db.Close() 482 } 483 }() 484 485 emptyDB, err := db.IsEmpty() 486 if err != nil { 487 return nil, err 488 } 489 490 expectedFormatBytes := []byte(dataformat.CurrentFormat) 491 if emptyDB { 492 // add format key to a new db 493 err := db.Put(formatKey, expectedFormatBytes, true) 494 if err != nil { 495 return nil, err 496 } 497 return &idStore{db, path}, nil 498 } 499 500 // verify the format is current for an existing db 501 format, err := db.Get(formatKey) 502 if err != nil { 503 return nil, err 504 } 505 if !bytes.Equal(format, expectedFormatBytes) { 506 logger.Errorf("The db at path [%s] contains data in unexpected format. expected data format = [%s] (%#v), data format = [%s] (%#v).", 507 path, dataformat.CurrentFormat, expectedFormatBytes, format, format) 508 return nil, &dataformat.ErrFormatMismatch{ 509 ExpectedFormat: dataformat.CurrentFormat, 510 Format: string(format), 511 DBInfo: fmt.Sprintf("leveldb for channel-IDs at [%s]", path), 512 } 513 } 514 return &idStore{db, path}, nil 515 } 516 517 // checkUpgradeEligibility checks if the format is eligible to upgrade. 518 // It returns true if the format is eligible to upgrade to the current format. 519 // It returns false if either the format is the current format or the db is empty. 520 // Otherwise, an ErrFormatMismatch is returned. 521 func (s *idStore) checkUpgradeEligibility() (bool, error) { 522 emptydb, err := s.db.IsEmpty() 523 if err != nil { 524 return false, err 525 } 526 if emptydb { 527 logger.Warnf("Ledger database %s is empty, nothing to upgrade", s.dbPath) 528 return false, nil 529 } 530 format, err := s.db.Get(formatKey) 531 if err != nil { 532 return false, err 533 } 534 if bytes.Equal(format, []byte(dataformat.CurrentFormat)) { 535 logger.Debugf("Ledger database %s has current data format, nothing to upgrade", s.dbPath) 536 return false, nil 537 } 538 if !bytes.Equal(format, []byte(dataformat.PreviousFormat)) { 539 err = &dataformat.ErrFormatMismatch{ 540 ExpectedFormat: dataformat.PreviousFormat, 541 Format: string(format), 542 DBInfo: fmt.Sprintf("leveldb for channel-IDs at [%s]", s.dbPath), 543 } 544 return false, err 545 } 546 return true, nil 547 } 548 549 func (s *idStore) upgradeFormat() error { 550 eligible, err := s.checkUpgradeEligibility() 551 if err != nil { 552 return err 553 } 554 if !eligible { 555 return nil 556 } 557 558 logger.Infof("Upgrading ledgerProvider database to the new format %s", dataformat.CurrentFormat) 559 560 batch := &leveldb.Batch{} 561 batch.Put(formatKey, []byte(dataformat.CurrentFormat)) 562 563 // add new metadata key for each ledger (channel) 564 metadata, err := protoutil.Marshal(&msgs.LedgerMetadata{Status: msgs.Status_ACTIVE}) 565 if err != nil { 566 logger.Errorf("Error marshalling ledger metadata: %s", err) 567 return errors.Wrapf(err, "error marshalling ledger metadata") 568 } 569 itr := s.db.GetIterator(ledgerKeyPrefix, ledgerKeyStop) 570 defer itr.Release() 571 for itr.Error() == nil && itr.Next() { 572 id := s.decodeLedgerID(itr.Key(), ledgerKeyPrefix) 573 batch.Put(s.encodeLedgerKey(id, metadataKeyPrefix), metadata) 574 } 575 if err = itr.Error(); err != nil { 576 logger.Errorf("Error while upgrading idStore format: %s", err) 577 return errors.Wrapf(err, "error while upgrading idStore format") 578 } 579 580 return s.db.WriteBatch(batch, true) 581 } 582 583 func (s *idStore) setUnderConstructionFlag(ledgerID string) error { 584 return s.db.Put(underConstructionLedgerKey, []byte(ledgerID), true) 585 } 586 587 func (s *idStore) unsetUnderConstructionFlag() error { 588 return s.db.Delete(underConstructionLedgerKey, true) 589 } 590 591 func (s *idStore) getUnderConstructionFlag() (string, error) { 592 val, err := s.db.Get(underConstructionLedgerKey) 593 if err != nil { 594 return "", err 595 } 596 return string(val), nil 597 } 598 599 func (s *idStore) createLedgerID(ledgerID string, gb *common.Block) error { 600 gbKey := s.encodeLedgerKey(ledgerID, ledgerKeyPrefix) 601 metadataKey := s.encodeLedgerKey(ledgerID, metadataKeyPrefix) 602 var val []byte 603 var metadata []byte 604 var err error 605 if val, err = s.db.Get(gbKey); err != nil { 606 return err 607 } 608 if val != nil { 609 return ErrLedgerIDExists 610 } 611 if val, err = proto.Marshal(gb); err != nil { 612 return err 613 } 614 if metadata, err = protoutil.Marshal(&msgs.LedgerMetadata{Status: msgs.Status_ACTIVE}); err != nil { 615 return err 616 } 617 batch := &leveldb.Batch{} 618 batch.Put(gbKey, val) 619 batch.Put(metadataKey, metadata) 620 batch.Delete(underConstructionLedgerKey) 621 return s.db.WriteBatch(batch, true) 622 } 623 624 func (s *idStore) updateLedgerStatus(ledgerID string, newStatus msgs.Status) error { 625 metadata, err := s.getLedgerMetadata(ledgerID) 626 if err != nil { 627 return err 628 } 629 if metadata == nil { 630 logger.Errorf("LedgerID [%s] does not exist", ledgerID) 631 return ErrNonExistingLedgerID 632 } 633 if metadata.Status == newStatus { 634 logger.Infof("Ledger [%s] is already in [%s] status, nothing to do", ledgerID, newStatus) 635 return nil 636 } 637 metadata.Status = newStatus 638 metadataBytes, err := proto.Marshal(metadata) 639 if err != nil { 640 logger.Errorf("Error marshalling ledger metadata: %s", err) 641 return errors.Wrapf(err, "error marshalling ledger metadata") 642 } 643 logger.Infof("Updating ledger [%s] status to [%s]", ledgerID, newStatus) 644 key := s.encodeLedgerKey(ledgerID, metadataKeyPrefix) 645 return s.db.Put(key, metadataBytes, true) 646 } 647 648 func (s *idStore) getLedgerMetadata(ledgerID string) (*msgs.LedgerMetadata, error) { 649 val, err := s.db.Get(s.encodeLedgerKey(ledgerID, metadataKeyPrefix)) 650 if val == nil || err != nil { 651 return nil, err 652 } 653 metadata := &msgs.LedgerMetadata{} 654 if err := proto.Unmarshal(val, metadata); err != nil { 655 logger.Errorf("Error unmarshalling ledger metadata: %s", err) 656 return nil, errors.Wrapf(err, "error unmarshalling ledger metadata") 657 } 658 return metadata, nil 659 } 660 661 func (s *idStore) ledgerIDExists(ledgerID string) (bool, error) { 662 key := s.encodeLedgerKey(ledgerID, ledgerKeyPrefix) 663 val, err := s.db.Get(key) 664 if err != nil { 665 return false, err 666 } 667 return val != nil, nil 668 } 669 670 // ledgerIDActive returns if a ledger is active and existed 671 func (s *idStore) ledgerIDActive(ledgerID string) (bool, bool, error) { 672 metadata, err := s.getLedgerMetadata(ledgerID) 673 if metadata == nil || err != nil { 674 return false, false, err 675 } 676 return metadata.Status == msgs.Status_ACTIVE, true, nil 677 } 678 679 func (s *idStore) getActiveLedgerIDs() ([]string, error) { 680 var ids []string 681 itr := s.db.GetIterator(metadataKeyPrefix, metadataKeyStop) 682 defer itr.Release() 683 for itr.Error() == nil && itr.Next() { 684 metadata := &msgs.LedgerMetadata{} 685 if err := proto.Unmarshal(itr.Value(), metadata); err != nil { 686 logger.Errorf("Error unmarshalling ledger metadata: %s", err) 687 return nil, errors.Wrapf(err, "error unmarshalling ledger metadata") 688 } 689 if metadata.Status == msgs.Status_ACTIVE { 690 id := s.decodeLedgerID(itr.Key(), metadataKeyPrefix) 691 ids = append(ids, id) 692 } 693 } 694 if err := itr.Error(); err != nil { 695 logger.Errorf("Error getting ledger ids from idStore: %s", err) 696 return nil, errors.Wrapf(err, "error getting ledger ids from idStore") 697 } 698 return ids, nil 699 } 700 701 func (s *idStore) close() { 702 s.db.Close() 703 } 704 705 func (s *idStore) encodeLedgerKey(ledgerID string, prefix []byte) []byte { 706 return append(prefix, []byte(ledgerID)...) 707 } 708 709 func (s *idStore) decodeLedgerID(key []byte, prefix []byte) string { 710 return string(key[len(prefix):]) 711 }