github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/kvledger/txmgmt/privacyenabledstate/snapshot.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package privacyenabledstate
     8  
     9  import (
    10  	"hash"
    11  	"path/filepath"
    12  
    13  	"github.com/osdi23p228/fabric/common/ledger/snapshot"
    14  	"github.com/osdi23p228/fabric/core/ledger/kvledger/txmgmt/statedb"
    15  )
    16  
    17  const (
    18  	snapshotFileFormat             = byte(1)
    19  	pubStateDataFileName           = "public_state.data"
    20  	pubStateMetadataFileName       = "public_state.metadata"
    21  	pvtStateHashesFileName         = "private_state_hashes.data"
    22  	pvtStateHashesMetadataFileName = "private_state_hashes.metadata"
    23  )
    24  
    25  // ExportPubStateAndPvtStateHashes generates four files in the specified dir. The files, public_state.data and public_state.metadata
    26  // contains the exported public state and the files private_state_hashes.data and private_state_hashes.data contain the exported private state hashes.
    27  // The file format for public state and the private state hashes are the same. The data files contains a series of tuple <key,value> and the metadata
    28  // files contains a series of tuple <namespace, num entries for the namespace in the data file>.
    29  func (s *DB) ExportPubStateAndPvtStateHashes(dir string, newHashFunc snapshot.NewHashFunc) (map[string][]byte, error) {
    30  	itr, dbValueFormat, err := s.GetFullScanIterator(isPvtdataNs)
    31  	if err != nil {
    32  		return nil, err
    33  	}
    34  	defer itr.Close()
    35  
    36  	var pubStateWriter *snapshotWriter
    37  	var pvtStateHashesWriter *snapshotWriter
    38  	for {
    39  		compositeKey, dbValue, err := itr.Next()
    40  		if err != nil {
    41  			return nil, err
    42  		}
    43  		if compositeKey == nil {
    44  			break
    45  		}
    46  		switch {
    47  		case isHashedDataNs(compositeKey.Namespace):
    48  			if pvtStateHashesWriter == nil { // encountered first time the pvt state hash element
    49  				pvtStateHashesWriter, err = newSnapshotWriter(
    50  					filepath.Join(dir, pvtStateHashesFileName),
    51  					filepath.Join(dir, pvtStateHashesMetadataFileName),
    52  					dbValueFormat,
    53  					newHashFunc,
    54  				)
    55  				if err != nil {
    56  					return nil, err
    57  				}
    58  				defer pvtStateHashesWriter.close()
    59  			}
    60  			if err := pvtStateHashesWriter.addData(compositeKey, dbValue); err != nil {
    61  				return nil, err
    62  			}
    63  		default:
    64  			if pubStateWriter == nil { // encountered first time the pub state element
    65  				pubStateWriter, err = newSnapshotWriter(
    66  					filepath.Join(dir, pubStateDataFileName),
    67  					filepath.Join(dir, pubStateMetadataFileName),
    68  					dbValueFormat,
    69  					newHashFunc,
    70  				)
    71  				if err != nil {
    72  					return nil, err
    73  				}
    74  				defer pubStateWriter.close()
    75  			}
    76  			if err := pubStateWriter.addData(compositeKey, dbValue); err != nil {
    77  				return nil, err
    78  			}
    79  		}
    80  	}
    81  
    82  	snapshotFilesInfo := map[string][]byte{}
    83  
    84  	if pubStateWriter != nil {
    85  		pubStateDataHash, pubStateMetadataHash, err := pubStateWriter.done()
    86  		if err != nil {
    87  			return nil, err
    88  		}
    89  		snapshotFilesInfo[pubStateDataFileName] = pubStateDataHash
    90  		snapshotFilesInfo[pubStateMetadataFileName] = pubStateMetadataHash
    91  	}
    92  
    93  	if pvtStateHashesWriter != nil {
    94  		pvtStateHahshesDataHash, pvtStateHashesMetadataHash, err := pvtStateHashesWriter.done()
    95  		if err != nil {
    96  			return nil, err
    97  		}
    98  		snapshotFilesInfo[pvtStateHashesFileName] = pvtStateHahshesDataHash
    99  		snapshotFilesInfo[pvtStateHashesMetadataFileName] = pvtStateHashesMetadataHash
   100  	}
   101  
   102  	return snapshotFilesInfo, nil
   103  }
   104  
   105  // snapshotWriter generates two files, a data file and a metadata file. The datafile contains a series of tuples <key, dbValue>
   106  // and the metadata file contains a series of tuples <namesapce, number-of-tuples-in-the-data-file-that-belong-to-this-namespace>
   107  type snapshotWriter struct {
   108  	dataFile                *snapshot.FileWriter
   109  	metadataFile            *snapshot.FileWriter
   110  	kvCountsPerNamespace    map[string]uint64
   111  	namespaceInsertionOrder []string
   112  }
   113  
   114  func newSnapshotWriter(
   115  	dataFilePath, metadataFilePath string,
   116  	dbValueFormat byte,
   117  	newHash func() (hash.Hash, error),
   118  ) (*snapshotWriter, error) {
   119  
   120  	var dataFile, metadataFile *snapshot.FileWriter
   121  	var err error
   122  	defer func() {
   123  		if err != nil {
   124  			dataFile.Close()
   125  			metadataFile.Close()
   126  		}
   127  	}()
   128  
   129  	dataFile, err = snapshot.CreateFile(dataFilePath, snapshotFileFormat, newHash)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	if err = dataFile.EncodeBytes([]byte{dbValueFormat}); err != nil {
   134  		return nil, err
   135  	}
   136  
   137  	metadataFile, err = snapshot.CreateFile(metadataFilePath, snapshotFileFormat, newHash)
   138  	if err != nil {
   139  		return nil, err
   140  	}
   141  	return &snapshotWriter{
   142  			dataFile:             dataFile,
   143  			metadataFile:         metadataFile,
   144  			kvCountsPerNamespace: map[string]uint64{},
   145  		},
   146  		nil
   147  }
   148  
   149  func (w *snapshotWriter) addData(ck *statedb.CompositeKey, dbValue []byte) error {
   150  	_, ok := w.kvCountsPerNamespace[ck.Namespace]
   151  	if !ok {
   152  		// new namespace begins
   153  		w.namespaceInsertionOrder = append(w.namespaceInsertionOrder, ck.Namespace)
   154  	}
   155  	w.kvCountsPerNamespace[ck.Namespace]++
   156  	if err := w.dataFile.EncodeString(ck.Key); err != nil {
   157  		return err
   158  	}
   159  	if err := w.dataFile.EncodeBytes(dbValue); err != nil {
   160  		return err
   161  	}
   162  	return nil
   163  }
   164  
   165  func (w *snapshotWriter) done() ([]byte, []byte, error) {
   166  	dataHash, err := w.dataFile.Done()
   167  	if err != nil {
   168  		return nil, nil, err
   169  	}
   170  
   171  	if err := w.metadataFile.EncodeUVarint(uint64(len(w.kvCountsPerNamespace))); err != nil {
   172  		return nil, nil, err
   173  	}
   174  	for _, ns := range w.namespaceInsertionOrder {
   175  		if err := w.metadataFile.EncodeString(ns); err != nil {
   176  			return nil, nil, err
   177  		}
   178  		if err := w.metadataFile.EncodeUVarint(w.kvCountsPerNamespace[ns]); err != nil {
   179  			return nil, nil, err
   180  		}
   181  	}
   182  	metadataHash, err := w.metadataFile.Done()
   183  	if err != nil {
   184  		return nil, nil, err
   185  	}
   186  	return dataHash, metadataHash, nil
   187  }
   188  
   189  func (w *snapshotWriter) close() {
   190  	if w == nil {
   191  		return
   192  	}
   193  	w.dataFile.Close()
   194  	w.metadataFile.Close()
   195  }