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