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