-
Notifications
You must be signed in to change notification settings - Fork 647
/
memory.go
107 lines (89 loc) · 2.33 KB
/
memory.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
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package atomic
import (
"bytes"
"sync"
"github.com/ava-labs/gecko/database"
"github.com/ava-labs/gecko/database/prefixdb"
"github.com/ava-labs/gecko/database/versiondb"
"github.com/ava-labs/gecko/ids"
"github.com/ava-labs/gecko/utils/codec"
"github.com/ava-labs/gecko/utils/hashing"
"github.com/ava-labs/gecko/utils/logging"
)
type rcLock struct {
lock sync.Mutex
count int
}
// Memory is the interface for shared memory inside a subnet
type Memory struct {
lock sync.Mutex
log logging.Logger
codec codec.Codec
locks map[[32]byte]*rcLock
db database.Database
}
// Initialize the SharedMemory
func (m *Memory) Initialize(log logging.Logger, db database.Database) {
m.log = log
m.codec = codec.NewDefault()
m.locks = make(map[[32]byte]*rcLock)
m.db = db
}
// NewSharedMemory returns a new SharedMemory
func (m *Memory) NewSharedMemory(id ids.ID) SharedMemory {
return &sharedMemory{
m: m,
thisChainID: id,
}
}
// GetDatabase returns and locks the provided DB
func (m *Memory) GetDatabase(sharedID ids.ID) (*versiondb.Database, database.Database) {
lock := m.makeLock(sharedID)
lock.Lock()
vdb := versiondb.New(m.db)
return vdb, prefixdb.New(sharedID.Bytes(), vdb)
}
// ReleaseDatabase unlocks the provided DB
func (m *Memory) ReleaseDatabase(sharedID ids.ID) {
lock := m.releaseLock(sharedID)
lock.Unlock()
}
func (m *Memory) makeLock(sharedID ids.ID) *sync.Mutex {
m.lock.Lock()
defer m.lock.Unlock()
key := sharedID.Key()
rc, exists := m.locks[key]
if !exists {
rc = &rcLock{}
m.locks[key] = rc
}
rc.count++
return &rc.lock
}
func (m *Memory) releaseLock(sharedID ids.ID) *sync.Mutex {
m.lock.Lock()
defer m.lock.Unlock()
key := sharedID.Key()
rc, exists := m.locks[key]
if !exists {
panic("Attemping to free an unknown lock")
}
rc.count--
if rc.count == 0 {
delete(m.locks, key)
}
return &rc.lock
}
// sharedID calculates the ID of the shared memory space
func (m *Memory) sharedID(id1, id2 ids.ID) ids.ID {
idKey1 := id1.Key()
idKey2 := id2.Key()
if bytes.Compare(idKey1[:], idKey2[:]) == 1 {
idKey1, idKey2 = idKey2, idKey1
}
combinedBytes, err := m.codec.Marshal([2][32]byte{idKey1, idKey2})
m.log.AssertNoError(err)
return ids.NewID(hashing.ComputeHash256Array(combinedBytes))
}