forked from couchbase/gocbcore
-
Notifications
You must be signed in to change notification settings - Fork 0
/
errmapcomponent.go
216 lines (194 loc) · 5.71 KB
/
errmapcomponent.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package gocbcore
import (
"encoding/json"
"github.com/couchbase/gocbcore/v10/memd"
)
type errMapComponent struct {
kvErrorMap kvErrorMapPtr
bucketName string
}
func newErrMapManager(bucketName string) *errMapComponent {
return &errMapComponent{
bucketName: bucketName,
}
}
func (errMgr *errMapComponent) getKvErrMapData(code memd.StatusCode) *kvErrorMapError {
errMap := errMgr.kvErrorMap.Get()
if errMap != nil {
if errData, ok := errMap.Errors[uint16(code)]; ok {
return &errData
}
}
return nil
}
func (errMgr *errMapComponent) StoreErrorMap(mapBytes []byte) {
errMap, err := parseKvErrorMap(mapBytes)
if err != nil {
logDebugf("Failed to parse kv error map (%s)", err)
return
}
logDebugf("Fetched error map: %+v", errMap)
// Check if we need to switch the agent itself to a better
// error map revision.
for {
origMap := errMgr.kvErrorMap.Get()
if origMap != nil && errMap.Revision < origMap.Revision {
break
}
if errMgr.kvErrorMap.Update(origMap, errMap) {
break
}
}
}
func (errMgr *errMapComponent) ShouldRetry(status memd.StatusCode) bool {
kvErrData := errMgr.getKvErrMapData(status)
if kvErrData != nil {
for _, attr := range kvErrData.Attributes {
if attr == "auto-retry" || attr == "retry-now" || attr == "retry-later" {
return true
}
}
}
return false
}
func (errMgr *errMapComponent) EnhanceKvError(err error, resp *memdQResponse, req *memdQRequest) error {
enhErr := &KeyValueError{
InnerError: err,
}
if req != nil {
enhErr.DocumentKey = string(req.Key)
enhErr.BucketName = errMgr.bucketName
enhErr.ScopeName = req.ScopeName
enhErr.CollectionName = req.CollectionName
enhErr.CollectionID = req.CollectionID
retryCount, reasons := req.Retries()
enhErr.RetryReasons = reasons
enhErr.RetryAttempts = retryCount
connInfo := req.ConnectionInfo()
enhErr.LastDispatchedTo = connInfo.lastDispatchedTo
enhErr.LastDispatchedFrom = connInfo.lastDispatchedFrom
enhErr.LastConnectionID = connInfo.lastConnectionID
}
if resp != nil {
enhErr.StatusCode = resp.Status
enhErr.Opaque = resp.Opaque
errMapData := errMgr.getKvErrMapData(enhErr.StatusCode)
if errMapData != nil {
enhErr.ErrorName = errMapData.Name
enhErr.ErrorDescription = errMapData.Description
}
if memd.DatatypeFlag(resp.Datatype)&memd.DatatypeFlagJSON != 0 {
var enhancedData struct {
Error struct {
Context string `json:"context"`
Ref string `json:"ref"`
} `json:"error"`
}
if parseErr := json.Unmarshal(resp.Value, &enhancedData); parseErr == nil {
enhErr.Context = enhancedData.Error.Context
enhErr.Ref = enhancedData.Error.Ref
}
}
}
return enhErr
}
func translateMemdError(err error, req *memdQRequest) error {
switch err {
case ErrMemdInvalidArgs:
return errInvalidArgument
case ErrMemdInternalError:
return errInternalServerFailure
case ErrMemdAccessError:
return errAuthenticationFailure
case ErrMemdAuthError:
return errAuthenticationFailure
case ErrMemdTmpFail:
return errTemporaryFailure
case ErrMemdBusy:
return errTemporaryFailure
case ErrMemdKeyExists:
if req.Command == memd.CmdReplace || (req.Command == memd.CmdDelete && req.Cas != 0) ||
(req.Command == memd.CmdSubDocMultiMutation && req.Cas != 0) {
return errCasMismatch
}
return errDocumentExists
case ErrMemdCollectionNotFound:
return errCollectionNotFound
case ErrMemdUnknownCommand:
return errUnsupportedOperation
case ErrMemdNotSupported:
return errUnsupportedOperation
case ErrMemdDCPStreamIDInvalid:
return errDCPStreamIDInvalid
case ErrMemdKeyNotFound:
return errDocumentNotFound
case ErrMemdLocked:
// BUGFIX(brett19): This resolves a bug in the server processing of the LOCKED
// operation where the server will respond with LOCKED rather than a CAS mismatch.
if req.Command == memd.CmdUnlockKey {
return errCasMismatch
}
return errDocumentLocked
case ErrMemdTooBig:
return errValueTooLarge
case ErrMemdSubDocNotJSON:
return errValueNotJSON
case ErrMemdDurabilityInvalidLevel:
return errDurabilityLevelNotAvailable
case ErrMemdDurabilityImpossible:
return errDurabilityImpossible
case ErrMemdSyncWriteAmbiguous:
return errDurabilityAmbiguous
case ErrMemdSyncWriteInProgess:
return errDurableWriteInProgress
case ErrMemdSyncWriteReCommitInProgress:
return errDurableWriteReCommitInProgress
case ErrMemdSubDocPathNotFound:
return errPathNotFound
case ErrMemdSubDocPathInvalid:
return errPathInvalid
case ErrMemdSubDocPathTooBig:
return errPathTooBig
case ErrMemdSubDocDocTooDeep:
return errPathTooDeep
case ErrMemdSubDocValueTooDeep:
return errValueTooDeep
case ErrMemdSubDocCantInsert:
return errValueInvalid
case ErrMemdSubDocNotJSON:
return errDocumentNotJSON
case ErrMemdSubDocBadRange:
return errNumberTooBig
case ErrMemdBadDelta:
return errDeltaInvalid
case ErrMemdSubDocBadDelta:
return errDeltaInvalid
case ErrMemdSubDocPathExists:
return errPathExists
case ErrXattrUnknownMacro:
return errXattrUnknownMacro
case ErrXattrInvalidFlagCombo:
return errXattrInvalidFlagCombo
case ErrXattrInvalidKeyCombo:
return errXattrInvalidKeyCombo
case ErrMemdSubDocXattrUnknownVAttr:
return errXattrUnknownVirtualAttribute
case ErrMemdSubDocXattrCannotModifyVAttr:
return errXattrCannotModifyVirtualAttribute
case ErrXattrInvalidOrder:
return errXattrInvalidOrder
case ErrMemdNotMyVBucket:
return errNotMyVBucket
case ErrMemdRateLimitedNetworkIngress:
return errRateLimitedFailure
case ErrMemdRateLimitedNetworkEgress:
return errRateLimitedFailure
case ErrMemdRateLimitedMaxConnections:
return errRateLimitedFailure
case ErrMemdRateLimitedMaxCommands:
return errRateLimitedFailure
case ErrMemdRateLimitedScopeSizeLimitExceeded:
return errQuotaLimitedFailure
}
return err
}