n3 2.2.10 → 2.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,9 @@ var _N3Writer = _interopRequireDefault(require("./N3Writer"));
9
9
  function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
10
10
  // **N3StreamWriter** serializes a quad stream into a text stream.
11
11
 
12
+ const MIN_CHUNK_SIZE = 16 * 1024;
13
+ const DEFAULT_FLUSH_DELAY_MS = 20;
14
+
12
15
  // ## Constructor
13
16
  class N3StreamWriter extends _readableStream.Transform {
14
17
  constructor(options) {
@@ -17,27 +20,77 @@ class N3StreamWriter extends _readableStream.Transform {
17
20
  writableObjectMode: true
18
21
  });
19
22
 
23
+ // Coalesce serialized fragments into larger stream chunks
24
+ this._buffer = '';
25
+
26
+ // Flush partial chunks after a bounded delay
27
+ this._flushTimer = null;
28
+ this._flushDelay = options && options.flushDelay !== undefined ? options.flushDelay : DEFAULT_FLUSH_DELAY_MS;
29
+
20
30
  // Set up writer with a dummy stream object
21
31
  const writer = this._writer = new _N3Writer.default({
22
- write: (quad, encoding, callback) => {
23
- this.push(quad);
32
+ write: (chunk, encoding, callback) => {
33
+ this._buffer += chunk;
34
+ if (this._buffer.length >= MIN_CHUNK_SIZE) this._pushBuffer();else if (this._flushTimer === null) this._armFlushTimer();
24
35
  callback && callback();
25
36
  },
26
37
  end: callback => {
38
+ this._pushBuffer();
27
39
  this.push(null);
28
40
  callback && callback();
29
41
  }
30
42
  }, options);
31
43
 
32
- // Implement Transform methods on top of writer
44
+ // Flush buffered output before serialization errors
45
+ let pendingDone = null;
46
+ const quadDone = error => {
47
+ const done = pendingDone;
48
+ pendingDone = null;
49
+ if (error) this._pushBuffer();
50
+ done(error);
51
+ };
33
52
  this._transform = (quad, encoding, done) => {
34
- writer.addQuad(quad, done);
53
+ pendingDone = done;
54
+ writer.addQuad(quad, quadDone);
35
55
  };
36
56
  this._flush = done => {
37
57
  writer.end(done);
38
58
  };
39
59
  }
40
60
 
61
+ // ### `_pushBuffer` flushes coalesced output to the stream queue
62
+ _pushBuffer() {
63
+ this._clearFlushTimer();
64
+ if (this._buffer !== '') {
65
+ this.push(this._buffer);
66
+ this._buffer = '';
67
+ }
68
+ }
69
+
70
+ // ### `_armFlushTimer` schedules a partial-chunk flush
71
+ _armFlushTimer() {
72
+ this._flushTimer = setTimeout(() => {
73
+ this._flushTimer = null;
74
+ this._pushBuffer();
75
+ }, this._flushDelay);
76
+ // Browser timers do not implement `unref`
77
+ this._flushTimer.unref && this._flushTimer.unref();
78
+ }
79
+
80
+ // ### `_clearFlushTimer` cancels a scheduled flush
81
+ _clearFlushTimer() {
82
+ if (this._flushTimer !== null) {
83
+ clearTimeout(this._flushTimer);
84
+ this._flushTimer = null;
85
+ }
86
+ }
87
+
88
+ // ### `_destroy` cancels a scheduled flush, so it cannot fire afterwards
89
+ _destroy(error, callback) {
90
+ this._clearFlushTimer();
91
+ super._destroy(error, callback);
92
+ }
93
+
41
94
  // ### Serializes a stream of quads
42
95
  import(stream) {
43
96
  stream.on('data', quad => {
@@ -47,6 +100,7 @@ class N3StreamWriter extends _readableStream.Transform {
47
100
  this.end();
48
101
  });
49
102
  stream.on('error', error => {
103
+ this._pushBuffer();
50
104
  this.emit('error', error);
51
105
  });
52
106
  stream.on('prefix', (prefix, iri) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "n3",
3
- "version": "2.2.10",
3
+ "version": "2.2.11",
4
4
  "description": "Lightning fast, asynchronous, streaming Turtle / N3 / RDF library.",
5
5
  "author": "Ruben Verborgh <ruben.verborgh@gmail.com>",
6
6
  "keywords": [
@@ -2,27 +2,89 @@
2
2
  import { Transform } from 'readable-stream';
3
3
  import N3Writer from './N3Writer';
4
4
 
5
+ const MIN_CHUNK_SIZE = 16 * 1024;
6
+ const DEFAULT_FLUSH_DELAY_MS = 20;
7
+
5
8
  // ## Constructor
6
9
  export default class N3StreamWriter extends Transform {
7
10
  constructor(options) {
8
11
  super({ encoding: 'utf8', writableObjectMode: true });
9
12
 
13
+ // Coalesce serialized fragments into larger stream chunks
14
+ this._buffer = '';
15
+
16
+ // Flush partial chunks after a bounded delay
17
+ this._flushTimer = null;
18
+ this._flushDelay = options && options.flushDelay !== undefined ?
19
+ options.flushDelay : DEFAULT_FLUSH_DELAY_MS;
20
+
10
21
  // Set up writer with a dummy stream object
11
22
  const writer = this._writer = new N3Writer({
12
- write: (quad, encoding, callback) => { this.push(quad); callback && callback(); },
13
- end: callback => { this.push(null); callback && callback(); },
23
+ write: (chunk, encoding, callback) => {
24
+ this._buffer += chunk;
25
+ if (this._buffer.length >= MIN_CHUNK_SIZE)
26
+ this._pushBuffer();
27
+ else if (this._flushTimer === null)
28
+ this._armFlushTimer();
29
+ callback && callback();
30
+ },
31
+ end: callback => { this._pushBuffer(); this.push(null); callback && callback(); },
14
32
  }, options);
15
33
 
16
- // Implement Transform methods on top of writer
17
- this._transform = (quad, encoding, done) => { writer.addQuad(quad, done); };
34
+ // Flush buffered output before serialization errors
35
+ let pendingDone = null;
36
+ const quadDone = error => {
37
+ const done = pendingDone;
38
+ pendingDone = null;
39
+ if (error)
40
+ this._pushBuffer();
41
+ done(error);
42
+ };
43
+ this._transform = (quad, encoding, done) => {
44
+ pendingDone = done;
45
+ writer.addQuad(quad, quadDone);
46
+ };
18
47
  this._flush = done => { writer.end(done); };
19
48
  }
20
49
 
50
+ // ### `_pushBuffer` flushes coalesced output to the stream queue
51
+ _pushBuffer() {
52
+ this._clearFlushTimer();
53
+ if (this._buffer !== '') {
54
+ this.push(this._buffer);
55
+ this._buffer = '';
56
+ }
57
+ }
58
+
59
+ // ### `_armFlushTimer` schedules a partial-chunk flush
60
+ _armFlushTimer() {
61
+ this._flushTimer = setTimeout(() => {
62
+ this._flushTimer = null;
63
+ this._pushBuffer();
64
+ }, this._flushDelay);
65
+ // Browser timers do not implement `unref`
66
+ this._flushTimer.unref && this._flushTimer.unref();
67
+ }
68
+
69
+ // ### `_clearFlushTimer` cancels a scheduled flush
70
+ _clearFlushTimer() {
71
+ if (this._flushTimer !== null) {
72
+ clearTimeout(this._flushTimer);
73
+ this._flushTimer = null;
74
+ }
75
+ }
76
+
77
+ // ### `_destroy` cancels a scheduled flush, so it cannot fire afterwards
78
+ _destroy(error, callback) {
79
+ this._clearFlushTimer();
80
+ super._destroy(error, callback);
81
+ }
82
+
21
83
  // ### Serializes a stream of quads
22
84
  import(stream) {
23
85
  stream.on('data', quad => { this.write(quad); });
24
86
  stream.on('end', () => { this.end(); });
25
- stream.on('error', error => { this.emit('error', error); });
87
+ stream.on('error', error => { this._pushBuffer(); this.emit('error', error); });
26
88
  stream.on('prefix', (prefix, iri) => { this._writer.addPrefix(prefix, iri); });
27
89
  return this;
28
90
  }