forked from keybase/client
-
Notifications
You must be signed in to change notification settings - Fork 0
/
block_ref_map.go
159 lines (137 loc) · 3.58 KB
/
block_ref_map.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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
// Copyright 2016 Keybase Inc. All rights reserved.
// Use of this source code is governed by a BSD
// license that can be found in the LICENSE file.
package libkbfs
import (
"fmt"
"github.com/keybase/client/go/kbfs/kbfsblock"
"github.com/keybase/client/go/protocol/keybase1"
)
type blockRefStatus int
const (
unknownBlockRef blockRefStatus = 0
liveBlockRef blockRefStatus = 1
archivedBlockRef blockRefStatus = 2
)
func (brf blockRefStatus) toBlockStatus() keybase1.BlockStatus {
switch brf {
case unknownBlockRef:
return keybase1.BlockStatus_UNKNOWN
case liveBlockRef:
return keybase1.BlockStatus_LIVE
case archivedBlockRef:
return keybase1.BlockStatus_ARCHIVED
default:
panic(fmt.Sprintf("Unknown ref status: %d", brf))
}
}
func (brf blockRefStatus) String() string {
switch brf {
case unknownBlockRef:
return "unknown"
case liveBlockRef:
return "live"
case archivedBlockRef:
return "archived"
default:
panic(fmt.Sprintf("Unknown ref status: %d", brf))
}
}
type blockContextMismatchError struct {
expected, actual kbfsblock.Context
}
func (e blockContextMismatchError) Error() string {
return fmt.Sprintf(
"Context mismatch: expected %s, got %s", e.expected, e.actual)
}
// TODO: Support unknown fields.
type blockRefEntry struct {
Status blockRefStatus
Context kbfsblock.Context
// mostRecentTag, if non-nil, is used by callers to figure out
// if an entry has been modified by something else. See
// blockRefMap.remove.
MostRecentTag string
}
func (e blockRefEntry) checkContext(context kbfsblock.Context) error {
if e.Context != context {
return blockContextMismatchError{e.Context, context}
}
return nil
}
// blockRefMap is a map with additional checking methods.
//
// TODO: Make this into a struct type that supports unknown fields.
type blockRefMap map[kbfsblock.RefNonce]blockRefEntry
func (refs blockRefMap) hasNonArchivedRef() bool {
for _, refEntry := range refs {
if refEntry.Status == liveBlockRef {
return true
}
}
return false
}
func (refs blockRefMap) getLiveCount() (count int) {
for _, refEntry := range refs {
if refEntry.Status == liveBlockRef {
count++
}
}
return count
}
func (refs blockRefMap) checkExists(context kbfsblock.Context) (
bool, blockRefStatus, error) {
refEntry, ok := refs[context.GetRefNonce()]
if !ok {
return false, unknownBlockRef, nil
}
err := refEntry.checkContext(context)
if err != nil {
return false, unknownBlockRef, err
}
return true, refEntry.Status, nil
}
func (refs blockRefMap) put(context kbfsblock.Context, status blockRefStatus,
tag string) error {
refNonce := context.GetRefNonce()
if refEntry, ok := refs[refNonce]; ok {
err := refEntry.checkContext(context)
if err != nil {
return err
}
}
refs[refNonce] = blockRefEntry{
Status: status,
Context: context,
MostRecentTag: tag,
}
return nil
}
// remove removes the entry with the given context, if any. If tag is
// non-empty, then the entry will be removed only if its most recent
// tag (passed in to put) matches the given one.
func (refs blockRefMap) remove(context kbfsblock.Context, tag string) error {
refNonce := context.GetRefNonce()
// If this check fails, this ref is already gone, which is not
// an error.
if refEntry, ok := refs[refNonce]; ok {
err := refEntry.checkContext(context)
if err != nil {
return err
}
if tag == "" || refEntry.MostRecentTag == tag {
delete(refs, refNonce)
}
}
return nil
}
func (refs blockRefMap) deepCopy() blockRefMap {
if len(refs) == 0 {
return nil
}
refsCopy := make(blockRefMap)
for k, v := range refs {
refsCopy[k] = v
}
return refsCopy
}