-
Notifications
You must be signed in to change notification settings - Fork 9
/
node.go
92 lines (76 loc) · 2.74 KB
/
node.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
/*
* Copyright 2017 Dgraph Labs, Inc. and Contributors
* Modifications copyright (C) 2017 Andy Kimball and Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package arenaskl
import (
"sync/atomic"
)
type links struct {
nextOffset uint32
prevOffset uint32
}
func (l *links) init(prevOffset, nextOffset uint32) {
l.nextOffset = nextOffset
l.prevOffset = prevOffset
}
type node struct {
// Immutable fields, so no need to lock to access key.
keyOffset uint32
keySize uint32
// Multiple parts of the value are encoded as a single uint64 so that it
// can be atomically loaded and stored:
// value offset: uint32 (bits 0-31)
// value size : uint16 (bits 32-47)
// metadata : uint16 (bits 48-63)
value uint64
// Most nodes do not need to use the full height of the tower, since the
// probability of each successive level decreases exponentially. Because
// these elements are never accessed, they do not need to be allocated.
// Therefore, when a node is allocated in the arena, its memory footprint
// is deliberately truncated to not include unneeded tower elements.
//
// All accesses to elements should use CAS operations, with no need to lock.
tower [maxHeight]links
}
func newNode(arena *Arena, height uint32) (nd *node, err error) {
if height < 1 || height > maxHeight {
panic("height cannot be less than one or greater than the max height")
}
// Compute the amount of the tower that will never be used, since the height
// is less than maxHeight.
unusedSize := (maxHeight - int(height)) * linksSize
nodeOffset, err := arena.Alloc(uint32(MaxNodeSize-unusedSize), uint32(unusedSize), Align8)
if err != nil {
return
}
nd = (*node)(arena.GetPointer(nodeOffset))
return
}
func (n *node) getKey(arena *Arena) []byte {
return arena.GetBytes(n.keyOffset, n.keySize)
}
func (n *node) nextOffset(h int) uint32 {
return atomic.LoadUint32(&n.tower[h].nextOffset)
}
func (n *node) prevOffset(h int) uint32 {
return atomic.LoadUint32(&n.tower[h].prevOffset)
}
func (n *node) casNextOffset(h int, old, val uint32) bool {
return atomic.CompareAndSwapUint32(&n.tower[h].nextOffset, old, val)
}
func (n *node) casPrevOffset(h int, old, val uint32) bool {
return atomic.CompareAndSwapUint32(&n.tower[h].prevOffset, old, val)
}