github.com/tenywen/fabric@v1.0.0-beta.0.20170620030522-a5b1ed380643/core/ledger/kvledger/history/historydb/historyleveldb/historyleveldb.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 historyleveldb
    18  
    19  import (
    20  	"github.com/hyperledger/fabric/common/flogging"
    21  	"github.com/hyperledger/fabric/common/ledger/blkstorage"
    22  	"github.com/hyperledger/fabric/common/ledger/util/leveldbhelper"
    23  	"github.com/hyperledger/fabric/core/ledger"
    24  	"github.com/hyperledger/fabric/core/ledger/kvledger/history/historydb"
    25  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    26  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    27  	"github.com/hyperledger/fabric/core/ledger/ledgerconfig"
    28  	"github.com/hyperledger/fabric/core/ledger/util"
    29  	"github.com/hyperledger/fabric/protos/common"
    30  	putils "github.com/hyperledger/fabric/protos/utils"
    31  )
    32  
    33  var logger = flogging.MustGetLogger("historyleveldb")
    34  
    35  var savePointKey = []byte{0x00}
    36  var emptyValue = []byte{}
    37  
    38  // HistoryDBProvider implements interface HistoryDBProvider
    39  type HistoryDBProvider struct {
    40  	dbProvider *leveldbhelper.Provider
    41  }
    42  
    43  // NewHistoryDBProvider instantiates HistoryDBProvider
    44  func NewHistoryDBProvider() *HistoryDBProvider {
    45  	dbPath := ledgerconfig.GetHistoryLevelDBPath()
    46  	logger.Debugf("constructing HistoryDBProvider dbPath=%s", dbPath)
    47  	dbProvider := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: dbPath})
    48  	return &HistoryDBProvider{dbProvider}
    49  }
    50  
    51  // GetDBHandle gets the handle to a named database
    52  func (provider *HistoryDBProvider) GetDBHandle(dbName string) (historydb.HistoryDB, error) {
    53  	return newHistoryDB(provider.dbProvider.GetDBHandle(dbName), dbName), nil
    54  }
    55  
    56  // Close closes the underlying db
    57  func (provider *HistoryDBProvider) Close() {
    58  	provider.dbProvider.Close()
    59  }
    60  
    61  // historyDB implements HistoryDB interface
    62  type historyDB struct {
    63  	db     *leveldbhelper.DBHandle
    64  	dbName string
    65  }
    66  
    67  // newHistoryDB constructs an instance of HistoryDB
    68  func newHistoryDB(db *leveldbhelper.DBHandle, dbName string) *historyDB {
    69  	return &historyDB{db, dbName}
    70  }
    71  
    72  // Open implements method in HistoryDB interface
    73  func (historyDB *historyDB) Open() error {
    74  	// do nothing because shared db is used
    75  	return nil
    76  }
    77  
    78  // Close implements method in HistoryDB interface
    79  func (historyDB *historyDB) Close() {
    80  	// do nothing because shared db is used
    81  }
    82  
    83  // Commit implements method in HistoryDB interface
    84  func (historyDB *historyDB) Commit(block *common.Block) error {
    85  
    86  	blockNo := block.Header.Number
    87  	//Set the starting tranNo to 0
    88  	var tranNo uint64
    89  
    90  	dbBatch := leveldbhelper.NewUpdateBatch()
    91  
    92  	logger.Debugf("Channel [%s]: Updating history database for blockNo [%v] with [%d] transactions",
    93  		historyDB.dbName, blockNo, len(block.Data.Data))
    94  
    95  	// Get the invalidation byte array for the block
    96  	txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
    97  	// Initialize txsFilter if it does not yet exist (e.g. during testing, for genesis block, etc)
    98  	if len(txsFilter) == 0 {
    99  		txsFilter = util.NewTxValidationFlags(len(block.Data.Data))
   100  		block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
   101  	}
   102  
   103  	// write each tran's write set to history db
   104  	for _, envBytes := range block.Data.Data {
   105  
   106  		// If the tran is marked as invalid, skip it
   107  		if txsFilter.IsInvalid(int(tranNo)) {
   108  			logger.Debugf("Channel [%s]: Skipping history write for invalid transaction number %d",
   109  				historyDB.dbName, tranNo)
   110  			tranNo++
   111  			continue
   112  		}
   113  
   114  		env, err := putils.GetEnvelopeFromBlock(envBytes)
   115  		if err != nil {
   116  			return err
   117  		}
   118  
   119  		payload, err := putils.GetPayload(env)
   120  		if err != nil {
   121  			return err
   122  		}
   123  
   124  		chdr, err := putils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
   125  		if err != nil {
   126  			return err
   127  		}
   128  
   129  		if common.HeaderType(chdr.Type) == common.HeaderType_ENDORSER_TRANSACTION {
   130  
   131  			// extract actions from the envelope message
   132  			respPayload, err := putils.GetActionFromEnvelope(envBytes)
   133  			if err != nil {
   134  				return err
   135  			}
   136  
   137  			//preparation for extracting RWSet from transaction
   138  			txRWSet := &rwsetutil.TxRwSet{}
   139  
   140  			// Get the Result from the Action and then Unmarshal
   141  			// it into a TxReadWriteSet using custom unmarshalling
   142  			if err = txRWSet.FromProtoBytes(respPayload.Results); err != nil {
   143  				return err
   144  			}
   145  			// for each transaction, loop through the namespaces and writesets
   146  			// and add a history record for each write
   147  			for _, nsRWSet := range txRWSet.NsRwSets {
   148  				ns := nsRWSet.NameSpace
   149  
   150  				for _, kvWrite := range nsRWSet.KvRwSet.Writes {
   151  					writeKey := kvWrite.Key
   152  
   153  					//composite key for history records is in the form ns~key~blockNo~tranNo
   154  					compositeHistoryKey := historydb.ConstructCompositeHistoryKey(ns, writeKey, blockNo, tranNo)
   155  
   156  					// No value is required, write an empty byte array (emptyValue) since Put() of nil is not allowed
   157  					dbBatch.Put(compositeHistoryKey, emptyValue)
   158  				}
   159  			}
   160  
   161  		} else {
   162  			logger.Debugf("Skipping transaction [%d] since it is not an endorsement transaction\n", tranNo)
   163  		}
   164  		tranNo++
   165  	}
   166  
   167  	// add savepoint for recovery purpose
   168  	height := version.NewHeight(blockNo, tranNo)
   169  	dbBatch.Put(savePointKey, height.ToBytes())
   170  
   171  	// write the block's history records and savepoint to LevelDB
   172  	if err := historyDB.db.WriteBatch(dbBatch, false); err != nil {
   173  		return err
   174  	}
   175  
   176  	logger.Debugf("Channel [%s]: Updates committed to history database for blockNo [%v]", historyDB.dbName, blockNo)
   177  	return nil
   178  }
   179  
   180  // NewHistoryQueryExecutor implements method in HistoryDB interface
   181  func (historyDB *historyDB) NewHistoryQueryExecutor(blockStore blkstorage.BlockStore) (ledger.HistoryQueryExecutor, error) {
   182  	return &LevelHistoryDBQueryExecutor{historyDB, blockStore}, nil
   183  }
   184  
   185  // GetBlockNumFromSavepoint implements method in HistoryDB interface
   186  func (historyDB *historyDB) GetLastSavepoint() (*version.Height, error) {
   187  	versionBytes, err := historyDB.db.Get(savePointKey)
   188  	if err != nil || versionBytes == nil {
   189  		return nil, err
   190  	}
   191  	height, _ := version.NewHeightFromBytes(versionBytes)
   192  	return height, nil
   193  }
   194  
   195  // ShouldRecover implements method in interface kvledger.Recoverer
   196  func (historyDB *historyDB) ShouldRecover(lastAvailableBlock uint64) (bool, uint64, error) {
   197  	if !ledgerconfig.IsHistoryDBEnabled() {
   198  		return false, 0, nil
   199  	}
   200  	savepoint, err := historyDB.GetLastSavepoint()
   201  	if err != nil {
   202  		return false, 0, err
   203  	}
   204  	if savepoint == nil {
   205  		return true, 0, nil
   206  	}
   207  	return savepoint.BlockNum != lastAvailableBlock, savepoint.BlockNum + 1, nil
   208  }
   209  
   210  // CommitLostBlock implements method in interface kvledger.Recoverer
   211  func (historyDB *historyDB) CommitLostBlock(block *common.Block) error {
   212  	if err := historyDB.Commit(block); err != nil {
   213  		return err
   214  	}
   215  	return nil
   216  }