1
1
'use strict' ;
2
- /*jshint latedef: nofunc */
2
+
3
+ var ReplyError = require ( './replyError' ) ;
3
4
4
5
/**
5
6
* Used for lengths only, faster perf on arrays / bulks
@@ -24,7 +25,6 @@ function parseSimpleString(parser) {
24
25
}
25
26
string += String . fromCharCode ( c1 ) ;
26
27
}
27
- return undefined ;
28
28
}
29
29
30
30
/**
@@ -33,12 +33,11 @@ function parseSimpleString(parser) {
33
33
* @param parser
34
34
* @param start
35
35
* @param end
36
- * @param noBuffer
37
36
* @returns {* }
38
37
*/
39
- function convertBufferRange ( parser , start , end , noBuffer ) {
38
+ function convertBufferRange ( parser , start , end ) {
40
39
// If returnBuffers is active, all return values are returned as buffers besides numbers and errors
41
- if ( ! noBuffer && parser . optionReturnBuffers === true ) {
40
+ if ( parser . optionReturnBuffers === true ) {
42
41
return parser . buffer . slice ( start , end ) ;
43
42
}
44
43
@@ -49,25 +48,20 @@ function convertBufferRange(parser, start, end, noBuffer) {
49
48
* Parse a '+' redis simple string response but forward the offsets
50
49
* onto convertBufferRange to generate a string.
51
50
* @param parser
52
- * @param noBuffer
53
51
* @returns {* }
54
52
*/
55
- function parseSimpleStringViaOffset ( parser , noBuffer ) {
53
+ function parseSimpleStringViaOffset ( parser ) {
56
54
var start = parser . offset ;
57
55
var offset = parser . offset ;
58
56
var length = parser . buffer . length ;
59
57
60
58
while ( offset < length ) {
61
59
var c1 = parser . buffer [ offset ++ ] ;
62
- if ( c1 === 13 ) { // \r
63
- var c2 = parser . buffer [ offset ++ ] ;
64
- if ( c2 === 10 ) { // \n
65
- parser . offset = offset ;
66
- return convertBufferRange ( parser , start , offset - 2 , noBuffer ) ;
67
- }
60
+ if ( c1 === 13 ) { // \r // Finding a \r is sufficient here, since in a simple string \r is always followed by \n
61
+ parser . offset = offset + 1 ;
62
+ return convertBufferRange ( parser , start , offset - 1 ) ;
68
63
}
69
64
}
70
- return undefined ;
71
65
}
72
66
73
67
/**
@@ -76,14 +70,7 @@ function parseSimpleStringViaOffset(parser, noBuffer) {
76
70
* @returns {* }
77
71
*/
78
72
function parseLength ( parser ) {
79
- var string ;
80
- /* istanbul ignore if */
81
- if ( parser . buffer . length > 4096 ) {
82
- string = parseSimpleStringViaOffset ( parser , true ) ;
83
- } else {
84
- string = parseSimpleString ( parser ) ;
85
- }
86
-
73
+ var string = parseSimpleString ( parser ) ;
87
74
if ( string !== undefined ) {
88
75
var length = + string ;
89
76
if ( length === - 1 ) {
@@ -99,7 +86,7 @@ function parseLength(parser) {
99
86
* @returns {* }
100
87
*/
101
88
function parseInteger ( parser ) {
102
- var string = parseSimpleStringViaOffset ( parser ) ;
89
+ var string = parseSimpleString ( parser ) ;
103
90
if ( string !== undefined ) {
104
91
// If stringNumbers is activated the parser always returns numbers as string
105
92
// This is important for big numbers (number > Math.pow(2, 53)) as js numbers
@@ -114,16 +101,18 @@ function parseInteger(parser) {
114
101
/**
115
102
* Parse a '$' redis bulk string response
116
103
* @param parser
117
- * @returns {null }
104
+ * @returns {* }
118
105
*/
119
106
function parseBulkString ( parser ) {
120
107
var length = parseLength ( parser ) ;
121
- /* jshint eqnull: true */
122
- if ( length == null ) {
108
+ if ( length === null || length === undefined ) {
123
109
return length ;
124
110
}
125
111
var offsetEnd = parser . offset + length ;
126
- if ( ( offsetEnd + 2 ) > parser . buffer . length ) {
112
+ if ( offsetEnd + 2 > parser . buffer . length ) {
113
+ parser . bufferCache . push ( parser . buffer ) ;
114
+ parser . totalChunkSize = parser . buffer . length ;
115
+ parser . bigStrSize = length + 2 ;
127
116
return ;
128
117
}
129
118
@@ -139,9 +128,9 @@ function parseBulkString(parser) {
139
128
* @returns {Error }
140
129
*/
141
130
function parseError ( parser ) {
142
- var string = parseSimpleStringViaOffset ( parser ) ;
143
- if ( string !== undefined ) {
144
- return new Error ( string ) ;
131
+ var str = parseSimpleString ( parser ) ;
132
+ if ( str !== undefined ) {
133
+ return new ReplyError ( str ) ;
145
134
}
146
135
}
147
136
@@ -162,8 +151,7 @@ function handleError(parser, error) {
162
151
*/
163
152
function parseArray ( parser ) {
164
153
var length = parseLength ( parser ) ;
165
- /* jshint eqnull: true */
166
- if ( length == null ) { // will break if using ===
154
+ if ( length === null || length === undefined ) {
167
155
return length ;
168
156
}
169
157
@@ -189,6 +177,7 @@ function parseArray(parser) {
189
177
* @param type
190
178
* @returns {* }
191
179
*/
180
+
192
181
function parseType ( parser , type ) {
193
182
switch ( type ) {
194
183
case 36 : // $
@@ -202,37 +191,24 @@ function parseType(parser, type) {
202
191
case 45 : // -
203
192
return parseError ( parser ) ;
204
193
default :
205
- return handleError ( parser , new Error ( 'Protocol error, got ' + JSON . stringify ( String . fromCharCode ( type ) ) + ' as reply type byte' ) ) ;
194
+ return handleError ( parser , new ReplyError ( 'Protocol error, got ' + JSON . stringify ( String . fromCharCode ( type ) ) + ' as reply type byte' ) ) ;
206
195
}
207
196
}
208
197
209
- /**
210
- * Quick buffer appending via buffer copy.
211
- * @param parser
212
- * @param buffer
213
- */
214
- function appendToBuffer ( parser , buffer ) {
215
- var oldLength = parser . buffer . length ;
216
- var remainingLength = oldLength - parser . offset ;
217
- var newLength = remainingLength + buffer . length ;
218
- var newBuffer = new Buffer ( newLength ) ;
219
- parser . buffer . copy ( newBuffer , 0 , parser . offset , oldLength ) ;
220
- buffer . copy ( newBuffer , remainingLength , 0 , buffer . length ) ;
221
- parser . buffer = newBuffer ;
222
- parser . offset = 0 ;
223
- }
224
-
225
198
/**
226
199
* Javascript Redis Parser
227
200
* @param options
228
201
* @constructor
229
202
*/
230
203
function JavascriptRedisParser ( options ) {
231
- this . optionReturnBuffers = ! ! options . return_buffers ;
232
- this . optionStringNumbers = ! ! options . string_numbers ;
204
+ this . optionReturnBuffers = ! ! options . returnBuffers ;
205
+ this . optionStringNumbers = ! ! options . stringNumbers ;
233
206
this . name = 'javascript' ;
234
207
this . offset = 0 ;
235
208
this . buffer = null ;
209
+ this . bigStrSize = 0 ;
210
+ this . totalChunkSize = 0 ;
211
+ this . bufferCache = [ ] ;
236
212
}
237
213
238
214
/**
@@ -243,8 +219,29 @@ JavascriptRedisParser.prototype.execute = function (buffer) {
243
219
if ( this . buffer === null ) {
244
220
this . buffer = buffer ;
245
221
this . offset = 0 ;
222
+ } else if ( this . bigStrSize === 0 ) {
223
+ var oldLength = this . buffer . length ;
224
+ var remainingLength = oldLength - this . offset ;
225
+ var newLength = remainingLength + buffer . length ;
226
+ var newBuffer = new Buffer ( newLength ) ;
227
+ this . buffer . copy ( newBuffer , 0 , this . offset , oldLength ) ;
228
+ buffer . copy ( newBuffer , remainingLength , 0 , buffer . length ) ;
229
+ this . buffer = newBuffer ;
230
+ this . offset = 0 ;
231
+ } else if ( this . totalChunkSize + buffer . length >= this . bigStrSize ) {
232
+ this . bufferCache . push ( buffer ) ;
233
+ if ( this . offset !== 0 ) {
234
+ this . bufferCache [ 0 ] = this . bufferCache [ 0 ] . slice ( this . offset ) ;
235
+ }
236
+ this . buffer = Buffer . concat ( this . bufferCache , this . totalChunkSize + buffer . length - this . offset ) ;
237
+ this . bigStrSize = 0 ;
238
+ this . totalChunkSize = 0 ;
239
+ this . bufferCache = [ ] ;
240
+ this . offset = 0 ;
246
241
} else {
247
- appendToBuffer ( this , buffer ) ;
242
+ this . bufferCache . push ( buffer ) ;
243
+ this . totalChunkSize += buffer . length ;
244
+ return ;
248
245
}
249
246
250
247
var length = this . buffer . length ;
0 commit comments