Skip to content

Commit 34c1591

Browse files
authored
Pipelining, TLS support, etc
- Some performance improvements by caching internal values. - TLS (SSL) support. - New `pipeline()`+`exec()` methods kindly borrowed from the [ioredis](https://github.com/redis/ioredis?tab=readme-ov-file#pipelining), which lets you to queue some commands in memory and then send them simultaneously to the server in a single (or several, if request body is too big) network call(s). Thanks to the Tarantool, which [made this possible](https://www.tarantool.io/en/doc/latest/dev_guide/internals/iproto/format/#packet-structure). This way the performance is significantly improved by 500-1600% - you can check it by yourself running `npm run benchmark-read` or `npm run benchmark-write`. Note that this feature doesn't replaces the Transaction model, which has some level of isolation. - Changed `const` declaration to `var` in order to support old Node.JS versions.
1 parent d43bc56 commit 34c1591

15 files changed

+305
-90
lines changed

Diff for: README.md

+28-4
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ Connection related custom events:
5151
| [options.username] | <code>string</code> | <code>null</code> | If set, client will authenticate with the value of this option when connected. |
5252
| [options.password] | <code>string</code> | <code>null</code> | If set, client will authenticate with the value of this option when connected. |
5353
| [options.timeout] | <code>number</code> | <code>0</code> | The milliseconds before a timeout occurs during the initial connection to the Tarantool server. |
54+
| [options.tls] | <code>Object</code> | <code>null</code> | If specified, forces to use `tls` module instead of the default `net`. In object properties you can specify any TLS-related options, e.g. from the [tls.createSecureContext()](https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions) |
5455
| [options.keepAlive] | <code>boolean</code> | <code>true</code> | Enables keep-alive functionality (recommended). |
5556
| [options.noDelay] | <code>boolean</code> | <code>true</code> | Disables the use of Nagle's algorithm (recommended). |
5657
| [options.lazyConnect] | <code>boolean</code> | <code>false</code> | By default, When a new `Tarantool` instance is created, it will connect to Tarantool server automatically. If you want to keep disconnected util a command is called, you can pass the `lazyConnect` option to the constructor. |
@@ -193,9 +194,9 @@ conn.select(512, 0, 1, 0, 'eq', [50]);
193194
conn.select('test', 'primary', 1, 0, 'eq', [50]);
194195
```
195196

196-
You can use space name or index name instead of id, but it will some requests for get this metadata. That information actual for delete, replace, insert, update too.
197+
You can use space name or index name instead of id, but this way some requests will be made to get and cache metadata. This stored information will be actual for delete, replace, insert, update too.
197198

198-
You can create space 'users' on Tarantool side, where the 'id' index is of UUID type:
199+
For tests, we will create a Space named 'users' on the Tarantool server-side, where the 'id' index is of UUID type:
199200

200201
```lua
201202
-- example schema of such space
@@ -288,7 +289,7 @@ conn.eval('return box.session.user()')
288289
})
289290
```
290291

291-
### tarantool.sql(query: String, bindParams: Array) -> <code>Promise</code>
292+
### tarantool.sql(query: String, bindParams: Array) <code>Promise</code>
292293

293294
It's accessible only in 2.1 tarantool.
294295

@@ -316,6 +317,24 @@ P.S. If you using lowercase in your space name you need to use a double quote fo
316317

317318
It doesn't work for space without format.
318319

320+
### tarantool.pipeline().<...>.exec()
321+
322+
Queue some commands in memory and then send them simultaneously to the server in a single (or several, if request body is too big) network call(s).
323+
This way the performance is significantly improved by more than 300% (depending on the number of pipelined commands - the bigger, the better)
324+
325+
Example:
326+
327+
```Javascript
328+
tarantool.pipeline()
329+
.insert('tags', ['tag_1', 1])
330+
.insert('tags', ['tag_2', 50])
331+
.sql('update "tags" set "amount" = 10 where "tag_id" = \'tag_1\'')
332+
.update('tags', 'tag_id', ['tag_2'], [['=', 'amount', 30]])
333+
.sql('select * from "tags"')
334+
.call('truncateTags')
335+
.exec()
336+
```
337+
319338
### tarantool.ping() ⇒ <code>Promise</code>
320339

321340
Promise resolve true.
@@ -338,14 +357,19 @@ It's ok you can do whatever you need. I add log options for some technical infor
338357

339358
## Changelog
340359

341-
### 4.0.0
360+
### 3.1.0
342361

343362
- Added 3 new msgpack extensions: UUID, Datetime, Decimal.
344363
- Connection object now accepts all options of `net.createConnection()`, including Unix socket path.
345364
- New `nonWritableHostPolicy` and related options, which improves a high availability capabilities without any 3rd parties.
346365
- Ability to disable the offline queue.
347366
- Fixed [bug with int32](https://github.com/tarantool/node-tarantool-driver/issues/48) numbers when it was encoded as floating. Use method `packInteger()` to solve this.
348367
- `selectCb()` now also accepts `spaceId` and `indexId` as their String names, not only their IDs.
368+
- Some performance improvements by caching internal values.
369+
- TLS (SSL) support.
370+
- New `pipeline()`+`exec()` methods kindly borrowed from the [ioredis](https://github.com/redis/ioredis?tab=readme-ov-file#pipelining), which lets you to queue some commands in memory and then send them simultaneously to the server in a single (or several, if request body is too big) network call(s). Thanks to the Tarantool, which [made this possible](https://www.tarantool.io/en/doc/latest/dev_guide/internals/iproto/format/#packet-structure).
371+
This way the performance is significantly improved by 500-1600% - you can check it yourself by running `npm run benchmark-read` or `npm run benchmark-write`.
372+
Note that this feature doesn't replaces the Transaction model, which has some level of isolation.
349373

350374
### 3.0.7
351375

Diff for: benchmark/box.lua

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
box.cfg{listen=3301}
22

3+
if not box.schema.user.exists('test') then
4+
box.schema.user.create('test')
5+
end
6+
37
user = box.user
48
if not user then
59
box.schema.user.grant('test', 'execute', 'universe')

Diff for: benchmark/read.js

+25-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ var conn = new Driver(process.argv[process.argv.length - 1], {lazyConnect: true}
1111

1212
conn.connect()
1313
.then(function(){
14-
1514
suite.add('select cb', {defer: true, fn: function(defer){
1615
function callback(){
1716
defer.resolve();
@@ -91,6 +90,31 @@ conn.connect()
9190
console.error(e, e.stack);
9291
}
9392
}});
93+
94+
suite.add('pipelined select by 10', {defer: true, fn: function(defer){
95+
var pipelinedConn = conn.pipeline()
96+
97+
for (var i=0;i<10;i++) {
98+
pipelinedConn.select('counter', 0, 1, 0, 'eq', ['test']);
99+
}
100+
101+
pipelinedConn.exec()
102+
.then(function(){ defer.resolve(); })
103+
.catch(function(e){ defer.reject(e); });
104+
}});
105+
106+
suite.add('pipelined select by 50', {defer: true, fn: function(defer){
107+
var pipelinedConn = conn.pipeline()
108+
109+
for (var i=0;i<50;i++) {
110+
pipelinedConn.select('counter', 0, 1, 0, 'eq', ['test']);
111+
}
112+
113+
pipelinedConn.exec()
114+
.then(function(){ defer.resolve(); })
115+
.catch(function(e){ defer.reject(e); });
116+
}});
117+
94118
suite
95119
.on('cycle', function(event) {
96120
console.log(String(event.target));

Diff for: benchmark/write.js

+25
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@ conn.connect()
3535
console.error(e, e.stack);
3636
}
3737
}});
38+
39+
suite.add('pipelined insert by 10', {defer: true, fn: function(defer){
40+
var pipelinedConn = conn.pipeline()
41+
42+
for (var i=0;i<10;i++) {
43+
pipelinedConn.insert('bench', [c++, {user: 'username', data: 'Some data.'}])
44+
}
45+
46+
pipelinedConn.exec()
47+
.then(function(){ defer.resolve(); })
48+
.catch(function(e){ defer.reject(e); })
49+
}});
50+
51+
suite.add('pipelined insert by 50', {defer: true, fn: function(defer){
52+
var pipelinedConn = conn.pipeline()
53+
54+
for (var i=0;i<50;i++) {
55+
pipelinedConn.insert('bench', [c++, {user: 'username', data: 'Some data.'}])
56+
}
57+
58+
pipelinedConn.exec()
59+
.then(function(){ defer.resolve(); })
60+
.catch(function(e){ defer.reject(e); })
61+
}});
62+
3863
suite
3964
.on('cycle', function(event) {
4065
console.log(String(event.target));

0 commit comments

Comments
 (0)