@@ -28,13 +28,15 @@ Writable.WritableState = WritableState;
28
28
29
29
var util = require ( 'util' ) ;
30
30
var Stream = require ( 'stream' ) ;
31
+ var debug = util . debuglog ( 'stream' ) ;
31
32
32
33
util . inherits ( Writable , Stream ) ;
33
34
34
35
function WriteReq ( chunk , encoding , cb ) {
35
36
this . chunk = chunk ;
36
37
this . encoding = encoding ;
37
38
this . callback = cb ;
39
+ this . next = null ;
38
40
}
39
41
40
42
function WritableState ( options , stream ) {
@@ -109,7 +111,8 @@ function WritableState(options, stream) {
109
111
// the amount that is being written when _write is called.
110
112
this . writelen = 0 ;
111
113
112
- this . buffer = [ ] ;
114
+ this . bufferedRequest = null ;
115
+ this . lastBufferedRequest = null ;
113
116
114
117
// number of pending user-supplied write callbacks
115
118
// this must be 0 before 'finish' can be emitted
@@ -123,6 +126,23 @@ function WritableState(options, stream) {
123
126
this . errorEmitted = false ;
124
127
}
125
128
129
+ WritableState . prototype . getBuffer = function writableStateGetBuffer ( ) {
130
+ var current = this . bufferedRequest ;
131
+ var out = [ ] ;
132
+ while ( current ) {
133
+ out . push ( current ) ;
134
+ current = current . next ;
135
+ }
136
+ return out ;
137
+ } ;
138
+
139
+ Object . defineProperty ( WritableState . prototype , 'buffer' , {
140
+ get : util . deprecate ( function ( ) {
141
+ return this . getBuffer ( ) ;
142
+ } , '_writableState.buffer is deprecated. Use ' +
143
+ '_writableState.getBuffer() instead.' )
144
+ } ) ;
145
+
126
146
function Writable ( options ) {
127
147
// Writable ctor is applied to Duplexes, though they're not
128
148
// instanceof Writable, they're instanceof Readable.
@@ -216,7 +236,7 @@ Writable.prototype.uncork = function() {
216
236
! state . corked &&
217
237
! state . finished &&
218
238
! state . bufferProcessing &&
219
- state . buffer . length )
239
+ state . bufferedRequest )
220
240
clearBuffer ( this , state ) ;
221
241
}
222
242
} ;
@@ -255,8 +275,15 @@ function writeOrBuffer(stream, state, chunk, encoding, cb) {
255
275
if ( ! ret )
256
276
state . needDrain = true ;
257
277
258
- if ( state . writing || state . corked )
259
- state . buffer . push ( new WriteReq ( chunk , encoding , cb ) ) ;
278
+ if ( state . writing || state . corked ) {
279
+ var last = state . lastBufferedRequest ;
280
+ state . lastBufferedRequest = new WriteReq ( chunk , encoding , cb ) ;
281
+ if ( last ) {
282
+ last . next = state . lastBufferedRequest ;
283
+ } else {
284
+ state . bufferedRequest = state . lastBufferedRequest ;
285
+ }
286
+ }
260
287
else
261
288
doWrite ( stream , state , false , len , chunk , encoding , cb ) ;
262
289
@@ -313,7 +340,7 @@ function onwrite(stream, er) {
313
340
if ( ! finished &&
314
341
! state . corked &&
315
342
! state . bufferProcessing &&
316
- state . buffer . length ) {
343
+ state . bufferedRequest ) {
317
344
clearBuffer ( stream , state ) ;
318
345
}
319
346
@@ -349,52 +376,53 @@ function onwriteDrain(stream, state) {
349
376
// if there's something in the buffer waiting, then process it
350
377
function clearBuffer ( stream , state ) {
351
378
state . bufferProcessing = true ;
379
+ var entry = state . bufferedRequest ;
352
380
353
- if ( stream . _writev && state . buffer . length > 1 ) {
381
+ if ( stream . _writev && entry && entry . next ) {
354
382
// Fast case, write everything using _writev()
383
+ var buffer = [ ] ;
355
384
var cbs = [ ] ;
356
- for ( var c = 0 ; c < state . buffer . length ; c ++ )
357
- cbs . push ( state . buffer [ c ] . callback ) ;
385
+ while ( entry ) {
386
+ cbs . push ( entry . callback ) ;
387
+ buffer . push ( entry ) ;
388
+ entry = entry . next ;
389
+ }
358
390
359
391
// count the one we are adding, as well.
360
392
// TODO(isaacs) clean this up
361
393
state . pendingcb ++ ;
362
- doWrite ( stream , state , true , state . length , state . buffer , '' , function ( err ) {
394
+ state . lastBufferedRequest = null ;
395
+ doWrite ( stream , state , true , state . length , buffer , '' , function ( err ) {
363
396
for ( var i = 0 ; i < cbs . length ; i ++ ) {
364
397
state . pendingcb -- ;
365
398
cbs [ i ] ( err ) ;
366
399
}
367
400
} ) ;
368
401
369
402
// Clear buffer
370
- state . buffer = [ ] ;
371
403
} else {
372
404
// Slow case, write chunks one-by-one
373
- for ( var c = 0 ; c < state . buffer . length ; c ++ ) {
374
- var entry = state . buffer [ c ] ;
405
+ while ( entry ) {
375
406
var chunk = entry . chunk ;
376
407
var encoding = entry . encoding ;
377
408
var cb = entry . callback ;
378
409
var len = state . objectMode ? 1 : chunk . length ;
379
410
380
411
doWrite ( stream , state , false , len , chunk , encoding , cb ) ;
381
-
412
+ entry = entry . next ;
382
413
// if we didn't call the onwrite immediately, then
383
414
// it means that we need to wait until it does.
384
415
// also, that means that the chunk and cb are currently
385
416
// being processed, so move the buffer counter past them.
386
417
if ( state . writing ) {
387
- c ++ ;
388
418
break ;
389
419
}
390
420
}
391
421
392
- if ( c < state . buffer . length )
393
- state . buffer = state . buffer . slice ( c ) ;
394
- else
395
- state . buffer . length = 0 ;
422
+ if ( entry === null )
423
+ state . lastBufferedRequest = null ;
396
424
}
397
-
425
+ state . bufferedRequest = entry ;
398
426
state . bufferProcessing = false ;
399
427
}
400
428
@@ -435,7 +463,7 @@ Writable.prototype.end = function(chunk, encoding, cb) {
435
463
function needFinish ( stream , state ) {
436
464
return ( state . ending &&
437
465
state . length === 0 &&
438
- state . buffer . length === 0 &&
466
+ state . bufferedRequest === null &&
439
467
! state . finished &&
440
468
! state . writing ) ;
441
469
}
0 commit comments