Skip to content

Commit 877562f

Browse files
authored
Merge pull request #160 from rueian/reduce-delegate-allocation
perf: reduce 90% of RedisResult memory allocation while delegating to RedisMessage
2 parents 0758427 + b39f995 commit 877562f

File tree

2 files changed

+159
-108
lines changed

2 files changed

+159
-108
lines changed

message.go

Lines changed: 158 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import (
1212

1313
const messageStructSize = int(unsafe.Sizeof(RedisMessage{}))
1414

15+
// Nil represents a Redis Nil message
16+
var Nil = &RedisError{typ: '_'}
17+
1518
// IsRedisNil is a handy method to check if error is redis nil response.
1619
// All redis nil response returns as an error.
1720
func IsRedisNil(err error) bool {
18-
if e, ok := err.(*RedisError); ok {
19-
return e.IsNil()
20-
}
21-
return false
21+
return err == Nil
2222
}
2323

2424
// RedisError is an error response or a nil message from redis instance
@@ -96,203 +96,253 @@ func (r RedisResult) NonRedisError() error {
9696
}
9797

9898
// Error returns either underlying error or redis error or nil
99-
func (r RedisResult) Error() error {
99+
func (r RedisResult) Error() (err error) {
100100
if r.err != nil {
101-
return r.err
102-
}
103-
if err := r.val.Error(); err != nil {
104-
return err
101+
err = r.err
102+
} else {
103+
err = r.val.Error()
105104
}
106-
return nil
105+
return
107106
}
108107

109108
// ToMessage retrieves the RedisMessage
110-
func (r RedisResult) ToMessage() (RedisMessage, error) {
111-
return r.val, r.Error()
109+
func (r RedisResult) ToMessage() (v RedisMessage, err error) {
110+
if r.err != nil {
111+
err = r.err
112+
} else {
113+
err = r.val.Error()
114+
}
115+
return r.val, err
112116
}
113117

114118
// ToInt64 delegates to RedisMessage.ToInt64
115-
func (r RedisResult) ToInt64() (int64, error) {
116-
if err := r.Error(); err != nil {
117-
return 0, err
119+
func (r RedisResult) ToInt64() (v int64, err error) {
120+
if r.err != nil {
121+
err = r.err
122+
} else {
123+
v, err = r.val.ToInt64()
118124
}
119-
return r.val.ToInt64()
125+
return
120126
}
121127

122128
// ToBool delegates to RedisMessage.ToBool
123-
func (r RedisResult) ToBool() (bool, error) {
124-
if err := r.Error(); err != nil {
125-
return false, err
129+
func (r RedisResult) ToBool() (v bool, err error) {
130+
if r.err != nil {
131+
err = r.err
132+
} else {
133+
v, err = r.val.ToBool()
126134
}
127-
return r.val.ToBool()
135+
return
128136
}
129137

130138
// ToFloat64 delegates to RedisMessage.ToFloat64
131-
func (r RedisResult) ToFloat64() (float64, error) {
132-
if err := r.Error(); err != nil {
133-
return 0, err
139+
func (r RedisResult) ToFloat64() (v float64, err error) {
140+
if r.err != nil {
141+
err = r.err
142+
} else {
143+
v, err = r.val.ToFloat64()
134144
}
135-
return r.val.ToFloat64()
145+
return
136146
}
137147

138148
// ToString delegates to RedisMessage.ToString
139-
func (r RedisResult) ToString() (string, error) {
140-
if err := r.Error(); err != nil {
141-
return "", err
149+
func (r RedisResult) ToString() (v string, err error) {
150+
if r.err != nil {
151+
err = r.err
152+
} else {
153+
v, err = r.val.ToString()
142154
}
143-
return r.val.ToString()
155+
return
144156
}
145157

146158
// AsReader delegates to RedisMessage.AsReader
147-
func (r RedisResult) AsReader() (reader io.Reader, err error) {
148-
if err := r.Error(); err != nil {
149-
return nil, err
159+
func (r RedisResult) AsReader() (v io.Reader, err error) {
160+
if r.err != nil {
161+
err = r.err
162+
} else {
163+
v, err = r.val.AsReader()
150164
}
151-
return r.val.AsReader()
165+
return
152166
}
153167

154168
// DecodeJSON delegates to RedisMessage.DecodeJSON
155-
func (r RedisResult) DecodeJSON(v interface{}) error {
156-
if err := r.Error(); err != nil {
157-
return err
169+
func (r RedisResult) DecodeJSON(v interface{}) (err error) {
170+
if r.err != nil {
171+
err = r.err
172+
} else {
173+
err = r.val.DecodeJSON(v)
158174
}
159-
return r.val.DecodeJSON(v)
175+
return
160176
}
161177

162178
// AsInt64 delegates to RedisMessage.AsInt64
163-
func (r RedisResult) AsInt64() (int64, error) {
164-
if err := r.Error(); err != nil {
165-
return 0, err
179+
func (r RedisResult) AsInt64() (v int64, err error) {
180+
if r.err != nil {
181+
err = r.err
182+
} else {
183+
v, err = r.val.AsInt64()
166184
}
167-
return r.val.AsInt64()
185+
return
168186
}
169187

170188
// AsBool delegates to RedisMessage.AsBool
171-
func (r RedisResult) AsBool() (bool, error) {
172-
if err := r.Error(); err != nil {
173-
return false, err
189+
func (r RedisResult) AsBool() (v bool, err error) {
190+
if r.err != nil {
191+
err = r.err
192+
} else {
193+
v, err = r.val.AsBool()
174194
}
175-
return r.val.AsBool()
195+
return
176196
}
177197

178198
// AsFloat64 delegates to RedisMessage.AsFloat64
179-
func (r RedisResult) AsFloat64() (float64, error) {
180-
if err := r.Error(); err != nil {
181-
return 0, err
199+
func (r RedisResult) AsFloat64() (v float64, err error) {
200+
if r.err != nil {
201+
err = r.err
202+
} else {
203+
v, err = r.val.AsFloat64()
182204
}
183-
return r.val.AsFloat64()
205+
return
184206
}
185207

186208
// ToArray delegates to RedisMessage.ToArray
187-
func (r RedisResult) ToArray() ([]RedisMessage, error) {
188-
if err := r.Error(); err != nil {
189-
return nil, err
209+
func (r RedisResult) ToArray() (v []RedisMessage, err error) {
210+
if r.err != nil {
211+
err = r.err
212+
} else {
213+
v, err = r.val.ToArray()
190214
}
191-
return r.val.ToArray()
215+
return
192216
}
193217

194218
// AsStrSlice delegates to RedisMessage.AsStrSlice
195-
func (r RedisResult) AsStrSlice() ([]string, error) {
196-
if err := r.Error(); err != nil {
197-
return nil, err
219+
func (r RedisResult) AsStrSlice() (v []string, err error) {
220+
if r.err != nil {
221+
err = r.err
222+
} else {
223+
v, err = r.val.AsStrSlice()
198224
}
199-
return r.val.AsStrSlice()
225+
return
200226
}
201227

202228
// AsIntSlice delegates to RedisMessage.AsIntSlice
203-
func (r RedisResult) AsIntSlice() ([]int64, error) {
204-
if err := r.Error(); err != nil {
205-
return nil, err
229+
func (r RedisResult) AsIntSlice() (v []int64, err error) {
230+
if r.err != nil {
231+
err = r.err
232+
} else {
233+
v, err = r.val.AsIntSlice()
206234
}
207-
return r.val.AsIntSlice()
235+
return
208236
}
209237

210238
// AsFloatSlice delegates to RedisMessage.AsFloatSlice
211-
func (r RedisResult) AsFloatSlice() ([]float64, error) {
212-
if err := r.Error(); err != nil {
213-
return nil, err
239+
func (r RedisResult) AsFloatSlice() (v []float64, err error) {
240+
if r.err != nil {
241+
err = r.err
242+
} else {
243+
v, err = r.val.AsFloatSlice()
214244
}
215-
return r.val.AsFloatSlice()
245+
return
216246
}
217247

218248
// AsXRangeEntry delegates to RedisMessage.AsXRangeEntry
219-
func (r RedisResult) AsXRangeEntry() (XRangeEntry, error) {
220-
if err := r.Error(); err != nil {
221-
return XRangeEntry{}, err
249+
func (r RedisResult) AsXRangeEntry() (v XRangeEntry, err error) {
250+
if r.err != nil {
251+
err = r.err
252+
} else {
253+
v, err = r.val.AsXRangeEntry()
222254
}
223-
return r.val.AsXRangeEntry()
255+
return
224256
}
225257

226258
// AsXRange delegates to RedisMessage.AsXRange
227-
func (r RedisResult) AsXRange() ([]XRangeEntry, error) {
228-
if err := r.Error(); err != nil {
229-
return nil, err
259+
func (r RedisResult) AsXRange() (v []XRangeEntry, err error) {
260+
if r.err != nil {
261+
err = r.err
262+
} else {
263+
v, err = r.val.AsXRange()
230264
}
231-
return r.val.AsXRange()
265+
return
232266
}
233267

234268
// AsZScore delegates to RedisMessage.AsZScore
235-
func (r RedisResult) AsZScore() (ZScore, error) {
236-
if err := r.Error(); err != nil {
237-
return ZScore{}, err
269+
func (r RedisResult) AsZScore() (v ZScore, err error) {
270+
if r.err != nil {
271+
err = r.err
272+
} else {
273+
v, err = r.val.AsZScore()
238274
}
239-
return r.val.AsZScore()
275+
return
240276
}
241277

242278
// AsZScores delegates to RedisMessage.AsZScores
243-
func (r RedisResult) AsZScores() ([]ZScore, error) {
244-
if err := r.Error(); err != nil {
245-
return nil, err
279+
func (r RedisResult) AsZScores() (v []ZScore, err error) {
280+
if r.err != nil {
281+
err = r.err
282+
} else {
283+
v, err = r.val.AsZScores()
246284
}
247-
return r.val.AsZScores()
285+
return
248286
}
249287

250288
// AsXRead delegates to RedisMessage.AsXRead
251-
func (r RedisResult) AsXRead() (map[string][]XRangeEntry, error) {
252-
if err := r.Error(); err != nil {
253-
return nil, err
289+
func (r RedisResult) AsXRead() (v map[string][]XRangeEntry, err error) {
290+
if r.err != nil {
291+
err = r.err
292+
} else {
293+
v, err = r.val.AsXRead()
254294
}
255-
return r.val.AsXRead()
295+
return
256296
}
257297

258298
// AsMap delegates to RedisMessage.AsMap
259-
func (r RedisResult) AsMap() (map[string]RedisMessage, error) {
260-
if err := r.Error(); err != nil {
261-
return nil, err
299+
func (r RedisResult) AsMap() (v map[string]RedisMessage, err error) {
300+
if r.err != nil {
301+
err = r.err
302+
} else {
303+
v, err = r.val.AsMap()
262304
}
263-
return r.val.AsMap()
305+
return
264306
}
265307

266308
// AsStrMap delegates to RedisMessage.AsStrMap
267-
func (r RedisResult) AsStrMap() (map[string]string, error) {
268-
if err := r.Error(); err != nil {
269-
return nil, err
309+
func (r RedisResult) AsStrMap() (v map[string]string, err error) {
310+
if r.err != nil {
311+
err = r.err
312+
} else {
313+
v, err = r.val.AsStrMap()
270314
}
271-
return r.val.AsStrMap()
315+
return
272316
}
273317

274318
// AsIntMap delegates to RedisMessage.AsIntMap
275-
func (r RedisResult) AsIntMap() (map[string]int64, error) {
276-
if err := r.Error(); err != nil {
277-
return nil, err
319+
func (r RedisResult) AsIntMap() (v map[string]int64, err error) {
320+
if r.err != nil {
321+
err = r.err
322+
} else {
323+
v, err = r.val.AsIntMap()
278324
}
279-
return r.val.AsIntMap()
325+
return
280326
}
281327

282328
// ToMap delegates to RedisMessage.ToMap
283-
func (r RedisResult) ToMap() (map[string]RedisMessage, error) {
284-
if err := r.Error(); err != nil {
285-
return nil, err
329+
func (r RedisResult) ToMap() (v map[string]RedisMessage, err error) {
330+
if r.err != nil {
331+
err = r.err
332+
} else {
333+
v, err = r.val.ToMap()
286334
}
287-
return r.val.ToMap()
335+
return
288336
}
289337

290338
// ToAny delegates to RedisMessage.ToAny
291-
func (r RedisResult) ToAny() (interface{}, error) {
292-
if err := r.Error(); err != nil {
293-
return nil, err
339+
func (r RedisResult) ToAny() (v interface{}, err error) {
340+
if r.err != nil {
341+
err = r.err
342+
} else {
343+
v, err = r.val.ToAny()
294344
}
295-
return r.val.ToAny()
345+
return
296346
}
297347

298348
// IsCacheHit delegates to RedisMessage.IsCacheHit
@@ -353,12 +403,13 @@ func (m *RedisMessage) IsMap() bool {
353403
// Error check if message is a redis error response, including nil response
354404
func (m *RedisMessage) Error() error {
355405
if m.typ == '_' {
356-
return (*RedisError)(m)
406+
return Nil
357407
}
358408
if m.typ == '-' || m.typ == '!' {
359409
// kvrocks: https://github.com/rueian/rueidis/issues/152#issuecomment-1333923750
360-
m.string = strings.TrimPrefix(m.string, "ERR ")
361-
return (*RedisError)(m)
410+
mm := *m
411+
mm.string = strings.TrimPrefix(m.string, "ERR ")
412+
return (*RedisError)(&mm)
362413
}
363414
return nil
364415
}

message_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
)
1212

1313
func TestIsRedisNil(t *testing.T) {
14-
err := &RedisError{typ: '_'}
14+
err := Nil
1515
if !IsRedisNil(err) {
1616
t.Fatal("IsRedisNil fail")
1717
}

0 commit comments

Comments
 (0)