github.com/klaytn/klaytn@v1.12.1/blockchain/state/state_object_encoder.go (about) 1 // Copyright 2019 The klaytn Authors 2 // This file is part of the klaytn library. 3 // 4 // The klaytn library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The klaytn library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the klaytn library. If not, see <http://www.gnu.org/licenses/>. 16 17 package state 18 19 import ( 20 "math" 21 "runtime" 22 23 "github.com/klaytn/klaytn/rlp" 24 "github.com/klaytn/klaytn/storage/statedb" 25 ) 26 27 var stateObjEncoderDefaultWorkers = calcNumStateObjectEncoderWorkers() 28 29 func calcNumStateObjectEncoderWorkers() int { 30 numWorkers := math.Ceil(float64(runtime.NumCPU()) / 4.0) 31 if numWorkers > stateObjEncoderMaxWorkers { 32 return stateObjEncoderMaxWorkers 33 } 34 return int(numWorkers) 35 } 36 37 const ( 38 stateObjEncoderMaxWorkers = 16 39 stateObjEncoderDefaultCap = 20000 40 ) 41 42 var stateObjEncoder = newStateObjectEncoder(stateObjEncoderDefaultWorkers, stateObjEncoderDefaultCap) 43 44 // newStateObjectEncoder generates a stateObjectEncoder and spawns goroutines 45 // which encode stateObject in parallel manner. 46 func newStateObjectEncoder(numGoRoutines, tasksChSize int) *stateObjectEncoder { 47 soe := &stateObjectEncoder{ 48 tasksCh: make(chan *stateObject, tasksChSize), 49 } 50 51 for i := 0; i < numGoRoutines; i++ { 52 go encodeStateObject(soe.tasksCh) 53 } 54 55 return soe 56 } 57 58 func getStateObjectEncoder(requiredChSize int) *stateObjectEncoder { 59 if requiredChSize <= cap(stateObjEncoder.tasksCh) { 60 return stateObjEncoder 61 } 62 return resetStateObjectEncoder(stateObjEncoderDefaultWorkers, requiredChSize) 63 } 64 65 // resetStateObjectEncoder closes existing tasksCh and assigns a new stateObjectEncoder. 66 func resetStateObjectEncoder(numGoRoutines, tasksChSize int) *stateObjectEncoder { 67 close(stateObjEncoder.tasksCh) 68 stateObjEncoder = newStateObjectEncoder(numGoRoutines, tasksChSize) 69 return stateObjEncoder 70 } 71 72 // stateObjectEncoder handles tasksCh and resultsCh 73 // to distribute the tasks and gather the results. 74 type stateObjectEncoder struct { 75 tasksCh chan *stateObject 76 } 77 78 func (soe *stateObjectEncoder) encode(so *stateObject) { 79 soe.tasksCh <- so 80 } 81 82 // encodeStateObject encodes the given stateObject and generates its hashKey and hexKey. 83 func encodeStateObject(tasksCh <-chan *stateObject) { 84 for stateObj := range tasksCh { 85 data, err := rlp.EncodeToBytes(stateObj) 86 if err != nil { 87 stateObj.encoded.Store(&encodedData{err: err}) 88 continue 89 } 90 addr := stateObj.Address() 91 hashKey, hexKey := statedb.GetHashAndHexKey(addr[:]) 92 stateObj.encoded.Store(&encodedData{data: data, trieHashKey: hashKey, trieHexKey: hexKey}) 93 } 94 }