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 }