github.com/iotexproject/iotex-core@v1.14.1-rc1/state/factory/patchstore.go (about) 1 // Copyright (c) 2021 IoTeX Foundation 2 // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability 3 // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed. 4 // This source code is governed by Apache License 2.0 that can be found in the LICENSE file. 5 6 package factory 7 8 import ( 9 "encoding/csv" 10 "encoding/hex" 11 "io" 12 "os" 13 "path/filepath" 14 "strconv" 15 16 "github.com/pkg/errors" 17 ) 18 19 const ( 20 _Put patchType = iota 21 _Delete 22 ) 23 24 type ( 25 patchType uint8 26 patch struct { 27 Type patchType 28 Namespace string 29 Key []byte 30 Value []byte 31 } 32 patchStore struct { 33 patchs map[uint64][]*patch 34 } 35 ) 36 37 /** 38 * patch format: 39 * height,type,namespace,key,value 40 * height: uint64, the height the record will be applied 41 * type: PUT or DELETE 42 * namespace: text string 43 * key: hex string 44 * value: hex string 45 */ 46 func newPatchStore(fpath string) (*patchStore, error) { 47 store := &patchStore{ 48 patchs: map[uint64][]*patch{}, 49 } 50 if fpath == "" { 51 return store, nil 52 } 53 file, err := os.Open(filepath.Clean(fpath)) 54 if err != nil { 55 return nil, errors.Wrapf(err, "failed to open kvstore patch, %s", fpath) 56 } 57 reader := csv.NewReader(file) 58 reader.FieldsPerRecord = -1 59 for { 60 record, err := reader.Read() 61 if err == io.EOF { 62 break 63 } 64 if err != nil { 65 return nil, errors.Wrap(err, "failed to read kvstore patch") 66 } 67 if len(record) < 4 { 68 return nil, errors.Errorf("wrong format %+v", record) 69 } 70 height, err := strconv.ParseUint(record[0], 10, 64) 71 if err != nil { 72 return nil, errors.Wrapf(err, "failed to parse height, %s", record[0]) 73 } 74 if _, ok := store.patchs[height]; !ok { 75 store.patchs[height] = []*patch{} 76 } 77 var t patchType 78 var value []byte 79 switch record[1] { 80 case "PUT": 81 t = _Put 82 if len(record) != 5 { 83 return nil, errors.Errorf("wrong put format %+v", record) 84 } 85 value, err = hex.DecodeString(record[4]) 86 if err != nil { 87 return nil, errors.Wrapf(err, "failed to parse value, %s", record[4]) 88 } 89 case "DELETE": 90 t = _Delete 91 default: 92 return nil, errors.Errorf("invalid patch type, %s", record[1]) 93 } 94 key, err := hex.DecodeString(record[3]) 95 if err != nil { 96 return nil, errors.Wrapf(err, "failed to parse key, %s", record[3]) 97 } 98 store.patchs[height] = append(store.patchs[height], &patch{ 99 Type: t, 100 Namespace: record[2], 101 Key: key, 102 Value: value, 103 }) 104 } 105 106 return store, nil 107 } 108 109 func (ps *patchStore) Get(height uint64) []*patch { 110 if ps == nil { 111 return nil 112 } 113 return ps.patchs[height] 114 }