pixl-server-storage 3.1.18 → 3.2.1
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.
- package/README.md +146 -134
- package/docs/API.md +149 -144
- package/docs/Hashes.md +20 -20
- package/docs/Indexer.md +11 -14
- package/docs/Lists.md +37 -37
- package/docs/Transactions.md +11 -11
- package/engines/Redis.js +39 -36
- package/engines/RedisCluster.js +10 -13
- package/engines/S3.js +88 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Overview
|
|
2
2
|
|
|
3
|
-
This module is a component for use in [pixl-server](https://www.
|
|
3
|
+
This module is a component for use in [pixl-server](https://www.github.com/jhuckaby/pixl-server). It implements a simple key/value storage system that can use multiple back-ends, such as [Amazon S3](https://aws.amazon.com/s3/), [Couchbase](http://www.couchbase.com/nosql-databases/couchbase-server), [Redis](https://redis.io/), or a local filesystem. It introduces the concept of a "chunked linked list", which supports extremely fast push, pop, shift, unshift, and random reads/writes. Also provided is a fast hash table implementation with key iteration, a transaction system, and an indexing and search system.
|
|
4
4
|
|
|
5
5
|
## Features at a Glance
|
|
6
6
|
|
|
@@ -86,27 +86,27 @@ Here is the table of contents for this current document:
|
|
|
86
86
|
|
|
87
87
|
Use [npm](https://www.npmjs.com/) to install the module:
|
|
88
88
|
|
|
89
|
-
```
|
|
89
|
+
```sh
|
|
90
90
|
npm install pixl-server pixl-server-storage
|
|
91
91
|
```
|
|
92
92
|
|
|
93
93
|
Here is a simple usage example. Note that the component's official name is `Storage`, so that is what you should use for the configuration key, and for gaining access to the component via your server object.
|
|
94
94
|
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
|
|
95
|
+
```js
|
|
96
|
+
const PixlServer = require('pixl-server');
|
|
97
|
+
let server = new PixlServer({
|
|
98
98
|
|
|
99
99
|
__name: 'MyServer',
|
|
100
100
|
__version: "1.0",
|
|
101
101
|
|
|
102
102
|
config: {
|
|
103
|
-
"log_dir": "/
|
|
103
|
+
"log_dir": "/let/log",
|
|
104
104
|
"debug_level": 9,
|
|
105
105
|
|
|
106
106
|
"Storage": {
|
|
107
107
|
"engine": "Filesystem",
|
|
108
108
|
"Filesystem": {
|
|
109
|
-
"base_dir": "/
|
|
109
|
+
"base_dir": "/let/data/myserver",
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
},
|
|
@@ -119,7 +119,7 @@ var server = new PixlServer({
|
|
|
119
119
|
|
|
120
120
|
server.startup( function() {
|
|
121
121
|
// server startup complete
|
|
122
|
-
|
|
122
|
+
let storage = server.Storage;
|
|
123
123
|
|
|
124
124
|
// store key
|
|
125
125
|
storage.put( 'test-key', { foo:"hello", bar:42 }, function(err) {
|
|
@@ -134,31 +134,31 @@ server.startup( function() {
|
|
|
134
134
|
} );
|
|
135
135
|
```
|
|
136
136
|
|
|
137
|
-
Notice how we are loading the [pixl-server](https://www.
|
|
137
|
+
Notice how we are loading the [pixl-server](https://www.github.com/jhuckaby/pixl-server) parent module, and then specifying [pixl-server-storage](https://www.github.com/jhuckaby/pixl-server-storage) as a component:
|
|
138
138
|
|
|
139
|
-
```
|
|
139
|
+
```js
|
|
140
140
|
components: [
|
|
141
141
|
require('pixl-server-storage')
|
|
142
142
|
]
|
|
143
143
|
```
|
|
144
144
|
|
|
145
|
-
This example is a very simple server configuration, which will start a local filesystem storage instance pointed at `/
|
|
145
|
+
This example is a very simple server configuration, which will start a local filesystem storage instance pointed at `/let/data/myserver` as a base directory. It then simply stores a test key, then fetches it back.
|
|
146
146
|
|
|
147
147
|
## Standalone Mode
|
|
148
148
|
|
|
149
|
-
If you want to access the storage component as a standalone class (i.e. not part of a [pixl-server](https://www.
|
|
149
|
+
If you want to access the storage component as a standalone class (i.e. not part of a [pixl-server](https://www.github.com/jhuckaby/pixl-server) server daemon), you can require the `pixl-server-storage/standalone` path and invoke it directly. This can be useful for things like simple CLI scripts. Example usage:
|
|
150
150
|
|
|
151
|
-
```
|
|
152
|
-
|
|
151
|
+
```js
|
|
152
|
+
const StandaloneStorage = require('pixl-server-storage/standalone');
|
|
153
153
|
|
|
154
|
-
|
|
154
|
+
const config = {
|
|
155
155
|
"engine": "Filesystem",
|
|
156
156
|
"Filesystem": {
|
|
157
|
-
"base_dir": "/
|
|
157
|
+
"base_dir": "/let/data/myserver"
|
|
158
158
|
}
|
|
159
159
|
};
|
|
160
160
|
|
|
161
|
-
|
|
161
|
+
let storage = new StandaloneStorage(config, function(err) {
|
|
162
162
|
if (err) throw err;
|
|
163
163
|
// storage system has started up and is ready to go
|
|
164
164
|
|
|
@@ -179,7 +179,7 @@ var storage = new StandaloneStorage(config, function(err) {
|
|
|
179
179
|
});
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
-
Please note that standalone mode does not perform standard [pixl-server](https://www.
|
|
182
|
+
Please note that standalone mode does not perform standard [pixl-server](https://www.github.com/jhuckaby/pixl-server) timer operations like emit `tick` and `minute` events, so things like performance metrics collection and [Daily Maintenance](#daily-maintenance) do not run. It also doesn't register standard [SIGINT / SIGTERM](https://nodejs.org/api/process.html#process_signal_events) signal listeners for handing shutdown, so these must be handled by your code.
|
|
183
183
|
|
|
184
184
|
# Configuration
|
|
185
185
|
|
|
@@ -189,11 +189,11 @@ The configuration for this component is set by passing in a `Storage` key in the
|
|
|
189
189
|
|
|
190
190
|
The `engine` property is used to declare the name of the back-end storage engine to use. Specifically, this is for using one of the built-in engine modules located in the `pixl-server-storage/engines/` directory. See [Engines](#engines) below for details. Example:
|
|
191
191
|
|
|
192
|
-
```
|
|
192
|
+
```json
|
|
193
193
|
{
|
|
194
194
|
"engine": "Filesystem",
|
|
195
195
|
"Filesystem": {
|
|
196
|
-
"base_dir": "/
|
|
196
|
+
"base_dir": "/let/data/myserver"
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
```
|
|
@@ -204,7 +204,7 @@ Note that the engine's own configuration should always go into a property named
|
|
|
204
204
|
|
|
205
205
|
The `engine_path` property can be used to load your own custom engine in any location. The path should be either absolute, or relative to the location of the `pixl-server-storage/` directory. Example:
|
|
206
206
|
|
|
207
|
-
```
|
|
207
|
+
```json
|
|
208
208
|
{
|
|
209
209
|
"engine": "MyCustomEngine",
|
|
210
210
|
"engine_path": "../../my_custom_storage_engine.js",
|
|
@@ -218,11 +218,11 @@ All engines must have a name, so you always need to declare a `engine` property
|
|
|
218
218
|
|
|
219
219
|
## list_page_size
|
|
220
220
|
|
|
221
|
-
The `list_page_size` property specifies the default page size (number of items per page) for new lists. However, you can override this per each list when creating them. See [Lists](docs/Lists.md) for details.
|
|
221
|
+
The `list_page_size` property specifies the default page size (number of items per page) for new lists. However, you can override this per each list when creating them. See [Lists](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Lists.md) for details.
|
|
222
222
|
|
|
223
223
|
## hash_page_size
|
|
224
224
|
|
|
225
|
-
The `hash_page_size` property specifies the default page size (number of items per page) for new hashes. However, you can override this per each hash when creating them. See [Hashes](docs/Hashes.md) for details.
|
|
225
|
+
The `hash_page_size` property specifies the default page size (number of items per page) for new hashes. However, you can override this per each hash when creating them. See [Hashes](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Hashes.md) for details.
|
|
226
226
|
|
|
227
227
|
## concurrency
|
|
228
228
|
|
|
@@ -232,7 +232,7 @@ The `concurrency` property allows some operations to be parallelized in the stor
|
|
|
232
232
|
|
|
233
233
|
The `maintenance` property allows the storage system to run routine maintenance, and is highly recommended for daemons that run 24x7. This is typically enabled to run nightly, and performs tasks such as deleting expired records. To enable it, set this to any `HH:MM` string where `HH` is the hour in 24-hour time and `MM` is the minute. Pad with a zero if either value is under 10. Example:
|
|
234
234
|
|
|
235
|
-
```
|
|
235
|
+
```js
|
|
236
236
|
{
|
|
237
237
|
"maintenance": "04:30" // run daily at 4:30 AM
|
|
238
238
|
}
|
|
@@ -246,13 +246,13 @@ The `log_event_types` property allows you to configure exactly which transaction
|
|
|
246
246
|
|
|
247
247
|
## max_recent_events
|
|
248
248
|
|
|
249
|
-
The `max_recent_events` property allows the storage system to track the latest N events in memory, which are then provided in the call to [getStats()](docs/API.md#getstats). For details, see the [Performance Metrics](#performance-metrics) section below.
|
|
249
|
+
The `max_recent_events` property allows the storage system to track the latest N events in memory, which are then provided in the call to [getStats()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#getstats). For details, see the [Performance Metrics](#performance-metrics) section below.
|
|
250
250
|
|
|
251
251
|
## expiration_updates
|
|
252
252
|
|
|
253
253
|
The `expiration_updates` property activates additional features in the [expiration system](#expiring-data). Namely, setting this property to `true` allows you to update expiration dates of existing records. Otherwise only a single expiration date may be set once per each record.
|
|
254
254
|
|
|
255
|
-
Note that this feature incurs additional overhead, because the expiration date of every record needs to be stored in a global [Hash](docs/Hashes.md). This slows down both the expiration set operation, and the nightly maintenance sweep to delete expired records. For this reason, the `expiration_dates` property defaults to `false` (disabled).
|
|
255
|
+
Note that this feature incurs additional overhead, because the expiration date of every record needs to be stored in a global [Hash](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Hashes.md). This slows down both the expiration set operation, and the nightly maintenance sweep to delete expired records. For this reason, the `expiration_dates` property defaults to `false` (disabled).
|
|
256
256
|
|
|
257
257
|
## lower_case_keys
|
|
258
258
|
|
|
@@ -285,11 +285,11 @@ Partial Filesystem Path:
|
|
|
285
285
|
|
|
286
286
|
The partial path is then combined with a base directory, which is configurable. Here is an example configuration:
|
|
287
287
|
|
|
288
|
-
```
|
|
288
|
+
```json
|
|
289
289
|
{
|
|
290
290
|
"engine": "Filesystem",
|
|
291
291
|
"Filesystem": {
|
|
292
|
-
"base_dir": "/
|
|
292
|
+
"base_dir": "/let/data/myserver"
|
|
293
293
|
}
|
|
294
294
|
}
|
|
295
295
|
```
|
|
@@ -297,7 +297,7 @@ The partial path is then combined with a base directory, which is configurable.
|
|
|
297
297
|
So, putting all this together, the `test1` key would be stored on disk at this location:
|
|
298
298
|
|
|
299
299
|
```
|
|
300
|
-
/
|
|
300
|
+
/let/data/myserver/5a/10/5e/5a105e8b9d40e1329780d62ea2265d8a.json
|
|
301
301
|
```
|
|
302
302
|
|
|
303
303
|
For binary records, the file extension will match whatever was in the key.
|
|
@@ -306,11 +306,11 @@ For binary records, the file extension will match whatever was in the key.
|
|
|
306
306
|
|
|
307
307
|
To help segment your application data into categories on the filesystem, an optional `key_namespaces` configuration parameter can be specified, and set to a true value. This will modify the key hashing algorithm to include a "prefix" directory, extracted from the plain key itself. Example configuration:
|
|
308
308
|
|
|
309
|
-
```
|
|
309
|
+
```json
|
|
310
310
|
{
|
|
311
311
|
"engine": "Filesystem",
|
|
312
312
|
"Filesystem": {
|
|
313
|
-
"base_dir": "/
|
|
313
|
+
"base_dir": "/let/data/myserver",
|
|
314
314
|
"key_namespaces": true
|
|
315
315
|
}
|
|
316
316
|
}
|
|
@@ -329,10 +329,10 @@ Partial Filesystem Path:
|
|
|
329
329
|
/users/01/9a/aa/019aaa6887e5ce3533dcc691b05e69e4.json
|
|
330
330
|
```
|
|
331
331
|
|
|
332
|
-
So in this case the `users` prefix is extracted from the plain key, and then inserted at the beginning of the hash directories. Here is the full filesystem path, assuming a base directory of `/
|
|
332
|
+
So in this case the `users` prefix is extracted from the plain key, and then inserted at the beginning of the hash directories. Here is the full filesystem path, assuming a base directory of `/let/data/myserver`:
|
|
333
333
|
|
|
334
334
|
```
|
|
335
|
-
/
|
|
335
|
+
/let/data/myserver/users/01/9a/aa/019aaa6887e5ce3533dcc691b05e69e4.json
|
|
336
336
|
```
|
|
337
337
|
|
|
338
338
|
In order to use key namespaces effectively, you need to make sure that *all* your plain keys contain some kind of namespace prefix, followed by a slash. The idea is, you can then store your app's data in different physical locations using symlinks. You can also determine how much disk space is taken up by each of your app's data categories, without having to walk all the hash directories.
|
|
@@ -341,11 +341,11 @@ In order to use key namespaces effectively, you need to make sure that *all* you
|
|
|
341
341
|
|
|
342
342
|
For testing purposes, or for small datasets, you can optionally set the `raw_file_paths` Filesystem configuration parameter to any true value. This will skip the MD5 hashing of all filesystem paths, and literally write them to the filesystem verbatim, as they come in (well, after [Key Normalization](#key-normalization) of course). Example configuration:
|
|
343
343
|
|
|
344
|
-
```
|
|
344
|
+
```json
|
|
345
345
|
{
|
|
346
346
|
"engine": "Filesystem",
|
|
347
347
|
"Filesystem": {
|
|
348
|
-
"base_dir": "/
|
|
348
|
+
"base_dir": "/let/data/myserver",
|
|
349
349
|
"raw_file_paths": true
|
|
350
350
|
}
|
|
351
351
|
}
|
|
@@ -354,7 +354,7 @@ For testing purposes, or for small datasets, you can optionally set the `raw_fil
|
|
|
354
354
|
So with raw file paths enabled our example key (`users/jhuckaby`) would literally end up on the filesystem right here:
|
|
355
355
|
|
|
356
356
|
```
|
|
357
|
-
/
|
|
357
|
+
/let/data/myserver/users/jhuckaby.json
|
|
358
358
|
```
|
|
359
359
|
|
|
360
360
|
Using this mode you can easily overwhelm a filesystem with too many files in a single directory, depending on how you format your keys. It is really only meant for testing purposes.
|
|
@@ -365,11 +365,11 @@ Note that if `raw_file_paths` is enabled, `key_namespaces` has no effect.
|
|
|
365
365
|
|
|
366
366
|
For complete, low-level control over the key hashing and directory layout, you can specify a key "template" via the `key_template` configuration property. This allows you to specify exactly how the directories are laid out, and whether the full plain key is part of the directory path, or just the MD5 hash. For example, consider this configuration:
|
|
367
367
|
|
|
368
|
-
```
|
|
368
|
+
```json
|
|
369
369
|
{
|
|
370
370
|
"engine": "Filesystem",
|
|
371
371
|
"Filesystem": {
|
|
372
|
-
"base_dir": "/
|
|
372
|
+
"base_dir": "/let/data/myserver",
|
|
373
373
|
"key_template": "##/##/##/[md5]"
|
|
374
374
|
}
|
|
375
375
|
}
|
|
@@ -389,11 +389,11 @@ You can optionally enable caching for the filesystem, which keeps a copy of the
|
|
|
389
389
|
|
|
390
390
|
To enable the filesystem cache, include a `cache` object in your `Filesystem` configuration with the following properties:
|
|
391
391
|
|
|
392
|
-
```
|
|
392
|
+
```json
|
|
393
393
|
{
|
|
394
394
|
"engine": "Filesystem",
|
|
395
395
|
"Filesystem": {
|
|
396
|
-
"base_dir": "/
|
|
396
|
+
"base_dir": "/let/data/myserver",
|
|
397
397
|
"cache": {
|
|
398
398
|
"enabled": true,
|
|
399
399
|
"maxItems": 1000,
|
|
@@ -419,7 +419,7 @@ Note that binary records are **not** cached. This system is for JSON records on
|
|
|
419
419
|
|
|
420
420
|
If you want to use [Amazon S3](http://aws.amazon.com/s3/) as a backing store, configure your storage thusly:
|
|
421
421
|
|
|
422
|
-
```
|
|
422
|
+
```json
|
|
423
423
|
{
|
|
424
424
|
"engine": "S3",
|
|
425
425
|
"AWS": {
|
|
@@ -463,7 +463,7 @@ Note that [binary keys](#storing-binary-blobs) already have file extensions, so
|
|
|
463
463
|
|
|
464
464
|
The S3 engine supports an optional key prefix, in case you are sharing a bucket with other applications, and want to keep all your app related records separate. To specify this, include a `keyPrefix` property in your `S3` object (this goes alongside the `params`, but not inside of it). Example:
|
|
465
465
|
|
|
466
|
-
```
|
|
466
|
+
```json
|
|
467
467
|
{
|
|
468
468
|
"S3": {
|
|
469
469
|
"keyPrefix": "myapp",
|
|
@@ -494,11 +494,13 @@ It is *highly* recommended that you enable caching for S3, which keeps a copy of
|
|
|
494
494
|
|
|
495
495
|
To enable the S3 cache, include a `cache` object in your `S3` configuration with the following properties:
|
|
496
496
|
|
|
497
|
-
```
|
|
498
|
-
|
|
499
|
-
"
|
|
500
|
-
|
|
501
|
-
|
|
497
|
+
```json
|
|
498
|
+
{
|
|
499
|
+
"cache": {
|
|
500
|
+
"enabled": true,
|
|
501
|
+
"maxItems": 1000,
|
|
502
|
+
"maxBytes": 10485760
|
|
503
|
+
}
|
|
502
504
|
}
|
|
503
505
|
```
|
|
504
506
|
|
|
@@ -522,13 +524,13 @@ Please note that as of this writing (April 2022), pixl-server-storage only suppo
|
|
|
522
524
|
|
|
523
525
|
If you want to use [Couchbase](http://www.couchbase.com/nosql-databases/couchbase-server) as a backing store, here is how to do so. First, you need to manually install the [couchbase](https://www.npmjs.com/package/couchbase) module into your app, and it **must be v2**:
|
|
524
526
|
|
|
525
|
-
```
|
|
527
|
+
```sh
|
|
526
528
|
npm install --save couchbase@2.6.12
|
|
527
529
|
```
|
|
528
530
|
|
|
529
531
|
Then configure your storage thusly:
|
|
530
532
|
|
|
531
|
-
```
|
|
533
|
+
```json
|
|
532
534
|
{
|
|
533
535
|
"engine": "Couchbase",
|
|
534
536
|
"Couchbase": {
|
|
@@ -556,26 +558,27 @@ Note that for Couchbase Server v5.0+ (Couchbase Node SDK 2.5+), you will have to
|
|
|
556
558
|
|
|
557
559
|
## Redis
|
|
558
560
|
|
|
559
|
-
If you want to use [Redis](https://redis.io/) as a backing store, here is how to do so. First, you need to manually install the [
|
|
561
|
+
If you want to use [Redis](https://redis.io/) as a backing store, here is how to do so. First, you need to manually install the [ioredis](https://www.npmjs.com/package/ioredis) module into your app:
|
|
560
562
|
|
|
561
|
-
```
|
|
562
|
-
npm install --save
|
|
563
|
+
```sh
|
|
564
|
+
npm install --save ioredis
|
|
563
565
|
```
|
|
564
566
|
|
|
565
567
|
Then configure your storage thusly:
|
|
566
568
|
|
|
567
|
-
```
|
|
569
|
+
```json
|
|
568
570
|
{
|
|
569
571
|
"engine": "Redis",
|
|
570
572
|
"Redis": {
|
|
571
573
|
"host": "127.0.0.1",
|
|
572
574
|
"port": 6379,
|
|
573
|
-
"keyPrefix": ""
|
|
575
|
+
"keyPrefix": "",
|
|
576
|
+
"keyTemplate": ""
|
|
574
577
|
}
|
|
575
578
|
}
|
|
576
579
|
```
|
|
577
580
|
|
|
578
|
-
Set the `host` and `port` for your own Redis server setup. Please see [Redis Options
|
|
581
|
+
Set the `host` and `port` for your own Redis server setup. Please see [Common Redis Options](https://redis.github.io/ioredis/interfaces/CommonRedisOptions.html) for other things you can include here, such as timeouts, authentication and database selection.
|
|
579
582
|
|
|
580
583
|
The optional `keyPrefix` property works similarly to the [S3 Key Prefix](#s3-key-prefix) feature. It allows you to prefix all the Redis keys with a common string, to separate your application's data in a shared database situation.
|
|
581
584
|
|
|
@@ -583,33 +586,39 @@ The optional `keyTemplate` property works similarly to the [S3 Key Template](#s3
|
|
|
583
586
|
|
|
584
587
|
### RedisCluster
|
|
585
588
|
|
|
586
|
-
If you want to use a Redis cluster (e.g. [AWS ElastiCache](https://aws.amazon.com/elasticache/)), then here is how to do that. First, you will need to manually install the following
|
|
589
|
+
If you want to use a Redis cluster (e.g. [AWS ElastiCache](https://aws.amazon.com/elasticache/)), then here is how to do that. First, you will need to manually install the following module into your app:
|
|
587
590
|
|
|
588
|
-
```
|
|
589
|
-
npm install --save ioredis
|
|
591
|
+
```sh
|
|
592
|
+
npm install --save ioredis
|
|
590
593
|
```
|
|
591
594
|
|
|
592
595
|
Then configure your storage thusly:
|
|
593
596
|
|
|
594
|
-
```
|
|
597
|
+
```json
|
|
595
598
|
{
|
|
596
599
|
"engine": "RedisCluster",
|
|
597
600
|
"RedisCluster": {
|
|
598
601
|
"host": "127.0.0.1",
|
|
599
602
|
"port": 6379,
|
|
600
|
-
"timeout": 1000,
|
|
601
603
|
"connectRetries": 5,
|
|
602
604
|
"clusterOpts": {
|
|
603
|
-
"scaleReads": "master"
|
|
605
|
+
"scaleReads": "master",
|
|
606
|
+
"redisOptions": {
|
|
607
|
+
"commandTimeout": 5000,
|
|
608
|
+
"connectTimeout": 5000
|
|
609
|
+
}
|
|
604
610
|
},
|
|
605
|
-
"keyPrefix": ""
|
|
611
|
+
"keyPrefix": "",
|
|
612
|
+
"keyTemplate": ""
|
|
606
613
|
}
|
|
607
614
|
}
|
|
608
615
|
```
|
|
609
616
|
|
|
610
|
-
Set the `host` and `port` for your own Redis cluster setup. The `host` should point to the cluster endpoint, **not** an individual Redis server.
|
|
617
|
+
Set the `host` and `port` for your own Redis cluster setup. The `host` should point to the cluster endpoint, **not** an individual Redis server. The `connectRetries` sets the number of retries on the initial socket connect operation (it defaults to `5`).
|
|
618
|
+
|
|
619
|
+
The `clusterOpts` property can hold several different cluster configuration options. Please see [Cluster Options](https://redis.github.io/ioredis/interfaces/ClusterOptions.html) for other things you can include here, such as `scaleReads` and `redisOptions`. For the `redisOptions` object, please see [Common Redis Options](https://redis.github.io/ioredis/interfaces/CommonRedisOptions.html) for other things you can include, such as timeouts, authentication and database selection.
|
|
611
620
|
|
|
612
|
-
|
|
621
|
+
It is **highly recommended** that you keep the `scaleReads` property set to `"master"`, for immediate consistency (required for [Lists](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Lists.md), [Hashes](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Hashes.md), [Transactions](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Transactions.md) and the [Indexer](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Indexer.md)).
|
|
613
622
|
|
|
614
623
|
The optional `keyPrefix` property works similarly to the [S3 Key Prefix](#s3-key-prefix) feature. It allows you to prefix all the Redis keys with a common string, to separate your application's data in a shared database situation.
|
|
615
624
|
|
|
@@ -619,13 +628,13 @@ The optional `keyTemplate` property works similarly to the [S3 Key Template](#s3
|
|
|
619
628
|
|
|
620
629
|
If you want to use [SQLite](https://sqlite.com/) as a backing store, here is how to do so. First, you need to manually install the [sqlite3](https://www.npmjs.com/package/sqlite3) module into your app:
|
|
621
630
|
|
|
622
|
-
```
|
|
631
|
+
```sh
|
|
623
632
|
npm install --save sqlite3
|
|
624
633
|
```
|
|
625
634
|
|
|
626
635
|
Then configure your storage thusly:
|
|
627
636
|
|
|
628
|
-
```
|
|
637
|
+
```json
|
|
629
638
|
{
|
|
630
639
|
"engine": "SQLite",
|
|
631
640
|
"SQLite": {
|
|
@@ -633,15 +642,22 @@ Then configure your storage thusly:
|
|
|
633
642
|
"filename": "sqlite.db",
|
|
634
643
|
"pragmas": {
|
|
635
644
|
"auto_vacuum": 0,
|
|
636
|
-
"cache_size": -100000
|
|
637
|
-
|
|
645
|
+
"cache_size": -100000,
|
|
646
|
+
"journal_mode": "WAL"
|
|
647
|
+
},
|
|
648
|
+
"keyPrefix": "",
|
|
649
|
+
"keyTemplate": ""
|
|
638
650
|
}
|
|
639
651
|
}
|
|
640
652
|
```
|
|
641
653
|
|
|
642
654
|
The `base_dir` defaults to the current working directory, and will be created on startup if necessary. The `filename` is the name of the SQLite DB file on disk (also created if necessary).
|
|
643
655
|
|
|
644
|
-
The optional `pragmas` object allows you set one or more [SQLite Pragmas](https://www.sqlite.org/pragma.html#toc) (configuration settings) on the database at startup. Here you can specify things such as [auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum)
|
|
656
|
+
The optional `pragmas` object allows you set one or more [SQLite Pragmas](https://www.sqlite.org/pragma.html#toc) (configuration settings) on the database at startup. Here you can specify things such as [auto_vacuum](https://www.sqlite.org/pragma.html#pragma_auto_vacuum), [cache_size](https://www.sqlite.org/pragma.html#pragma_cache_size) and [journal_mode](https://www.sqlite.org/pragma.html#pragma_journal_mode), among many others.
|
|
657
|
+
|
|
658
|
+
The optional `keyPrefix` property works similarly to the [S3 Key Prefix](#s3-key-prefix) feature. It allows you to prefix all the SQLite keys with a common string, to separate your application's data in a shared database situation.
|
|
659
|
+
|
|
660
|
+
The optional `keyTemplate` property works similarly to the [S3 Key Template](#s3-key-template) feature. It allows you to specify an exact layout of MD5 hash characters, which can be prefixed, mixed in with or postfixed after the key.
|
|
645
661
|
|
|
646
662
|
## Hybrid
|
|
647
663
|
|
|
@@ -667,7 +683,7 @@ The `Hybrid` engine only has two properties, `docEngine` and `binaryEngine`. Th
|
|
|
667
683
|
"binaryEngine": "S3"
|
|
668
684
|
},
|
|
669
685
|
"Filesystem": {
|
|
670
|
-
"base_dir": "/
|
|
686
|
+
"base_dir": "/let/data/myserver"
|
|
671
687
|
},
|
|
672
688
|
"AWS": {
|
|
673
689
|
"accessKeyId": "YOUR_AMAZON_ACCESS_KEY",
|
|
@@ -720,15 +736,15 @@ The storage module supports the following basic methods for typical operations.
|
|
|
720
736
|
|
|
721
737
|
The code examples all assume you have your preloaded `Storage` component instance in a local variable named `storage`. The component instance can be retrieved from a running server like this:
|
|
722
738
|
|
|
723
|
-
```
|
|
724
|
-
|
|
739
|
+
```js
|
|
740
|
+
let storage = server.Storage;
|
|
725
741
|
```
|
|
726
742
|
|
|
727
743
|
## Storing Records
|
|
728
744
|
|
|
729
|
-
To store a record, call the [put()](docs/API.md#put) method. Pass in a key, a value, and a callback. The value may be an Object (which is automatically serialized to JSON), or a `Buffer` for a binary blob (see [Storing Binary Blobs](#storing-binary-blobs) below). If the record doesn't exist, it is created, otherwise it is replaced.
|
|
745
|
+
To store a record, call the [put()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#put) method. Pass in a key, a value, and a callback. The value may be an Object (which is automatically serialized to JSON), or a `Buffer` for a binary blob (see [Storing Binary Blobs](#storing-binary-blobs) below). If the record doesn't exist, it is created, otherwise it is replaced.
|
|
730
746
|
|
|
731
|
-
```
|
|
747
|
+
```js
|
|
732
748
|
storage.put( 'test1', { foo: 'bar1' }, function(err) {
|
|
733
749
|
if (err) throw err;
|
|
734
750
|
} );
|
|
@@ -736,9 +752,9 @@ storage.put( 'test1', { foo: 'bar1' }, function(err) {
|
|
|
736
752
|
|
|
737
753
|
## Fetching Records
|
|
738
754
|
|
|
739
|
-
To fetch a record, call the [get()](docs/API.md#get) method. Pass in a key, and a callback. The data returned will be parsed back into an Object if JSON, or a raw `Buffer` object will be returned for binary records.
|
|
755
|
+
To fetch a record, call the [get()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#get) method. Pass in a key, and a callback. The data returned will be parsed back into an Object if JSON, or a raw `Buffer` object will be returned for binary records.
|
|
740
756
|
|
|
741
|
-
```
|
|
757
|
+
```js
|
|
742
758
|
storage.get( 'test1', function(err, data) {
|
|
743
759
|
if (err) throw err;
|
|
744
760
|
} );
|
|
@@ -746,7 +762,7 @@ storage.get( 'test1', function(err, data) {
|
|
|
746
762
|
|
|
747
763
|
If you try to fetch a nonexistent record, a special error object will be passed to your callback with its `code` property set to `NoSuchKey`. This is a special case allowing you to easily differentiate a "record not found" error from another, more severe I/O error. Example:
|
|
748
764
|
|
|
749
|
-
```
|
|
765
|
+
```js
|
|
750
766
|
storage.get( 'this_key_does_not_exist', function(err, data) {
|
|
751
767
|
if (err) {
|
|
752
768
|
if (err.code == 'NoSuchKey') {
|
|
@@ -762,9 +778,9 @@ storage.get( 'this_key_does_not_exist', function(err, data) {
|
|
|
762
778
|
} );
|
|
763
779
|
```
|
|
764
780
|
|
|
765
|
-
Some engines also allow you to "head" (i.e. ping) an object to retrieve some metadata about it, without fetching the value. To do this, call the [head()](docs/API.md#head) method, and pass in the key. The metadata usually consists of the size (`len`) and last modification date (`mod`). Example:
|
|
781
|
+
Some engines also allow you to "head" (i.e. ping) an object to retrieve some metadata about it, without fetching the value. To do this, call the [head()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#head) method, and pass in the key. The metadata usually consists of the size (`len`) and last modification date (`mod`). Example:
|
|
766
782
|
|
|
767
|
-
```
|
|
783
|
+
```js
|
|
768
784
|
storage.head( 'test1', function(err, data) {
|
|
769
785
|
if (err) throw err;
|
|
770
786
|
// data.mod
|
|
@@ -776,7 +792,7 @@ Note that the [Couchbase](#couchbase) engine does not support `head`, but the [A
|
|
|
776
792
|
|
|
777
793
|
You can fetch multiple records at once by calling `getMulti()` and passing in array of keys. Example:
|
|
778
794
|
|
|
779
|
-
```
|
|
795
|
+
```js
|
|
780
796
|
storage.getMulti( ['test1', 'test2', 'test3'], function(err, values) {
|
|
781
797
|
if (err) throw err;
|
|
782
798
|
// values[0] will be the test1 record.
|
|
@@ -787,9 +803,9 @@ storage.getMulti( ['test1', 'test2', 'test3'], function(err, values) {
|
|
|
787
803
|
|
|
788
804
|
## Copying Records
|
|
789
805
|
|
|
790
|
-
To make a copy of a record and store it under a new key, call the [copy()](docs/API.md#copy) method. Pass in the old key, new key, and a callback.
|
|
806
|
+
To make a copy of a record and store it under a new key, call the [copy()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#copy) method. Pass in the old key, new key, and a callback.
|
|
791
807
|
|
|
792
|
-
```
|
|
808
|
+
```js
|
|
793
809
|
storage.copy( 'test1', 'test2', function(err) {
|
|
794
810
|
if (err) throw err;
|
|
795
811
|
} );
|
|
@@ -799,9 +815,9 @@ storage.copy( 'test1', 'test2', function(err) {
|
|
|
799
815
|
|
|
800
816
|
## Renaming Records
|
|
801
817
|
|
|
802
|
-
To rename a record, call the [rename()](docs/API.md#rename) method. Pass in the old key, new key, and a callback.
|
|
818
|
+
To rename a record, call the [rename()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#rename) method. Pass in the old key, new key, and a callback.
|
|
803
819
|
|
|
804
|
-
```
|
|
820
|
+
```js
|
|
805
821
|
storage.rename( 'test1', 'test2', function(err) {
|
|
806
822
|
if (err) throw err;
|
|
807
823
|
} );
|
|
@@ -811,9 +827,9 @@ storage.rename( 'test1', 'test2', function(err) {
|
|
|
811
827
|
|
|
812
828
|
## Deleting Records
|
|
813
829
|
|
|
814
|
-
To delete a record, call the [delete()](docs/API.md#delete) method. This is immediate and permanent. Pass in the key, and a callback.
|
|
830
|
+
To delete a record, call the [delete()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#delete) method. This is immediate and permanent. Pass in the key, and a callback.
|
|
815
831
|
|
|
816
|
-
```
|
|
832
|
+
```js
|
|
817
833
|
storage.delete( 'test1', function(err) {
|
|
818
834
|
if (err) throw err;
|
|
819
835
|
} );
|
|
@@ -823,9 +839,9 @@ storage.delete( 'test1', function(err) {
|
|
|
823
839
|
|
|
824
840
|
To store a binary value, pass a filled `Buffer` object as the value, and specify a key ending in a "file extension", e.g. `.gif`. The latter requirement is so the engine can detect which records are binary and which are JSON, just by looking at the key. Example:
|
|
825
841
|
|
|
826
|
-
```
|
|
827
|
-
|
|
828
|
-
|
|
842
|
+
```js
|
|
843
|
+
const fs = require('fs');
|
|
844
|
+
let buffer = fs.readFileSync('picture.gif');
|
|
829
845
|
storage.put( 'test1.gif', buffer, function(err) {
|
|
830
846
|
if (err) throw err;
|
|
831
847
|
} );
|
|
@@ -833,8 +849,8 @@ storage.put( 'test1.gif', buffer, function(err) {
|
|
|
833
849
|
|
|
834
850
|
When fetching a binary record, a `Buffer` object will be passed to your callback:
|
|
835
851
|
|
|
836
|
-
```
|
|
837
|
-
|
|
852
|
+
```js
|
|
853
|
+
const fs = require('fs');
|
|
838
854
|
storage.get( 'test1.gif', function(err, buffer) {
|
|
839
855
|
if (err) throw err;
|
|
840
856
|
fs.writeFileSync('picture.gif', buffer);
|
|
@@ -843,13 +859,13 @@ storage.get( 'test1.gif', function(err, buffer) {
|
|
|
843
859
|
|
|
844
860
|
# Using Streams
|
|
845
861
|
|
|
846
|
-
You can store and fetch binary records using [streams](https://nodejs.org/api/stream.html), so as to not load any content into memory. This can be used to manage extremely large files in a memory-limited environment. Note that the record content is treated as binary, so the keys *must* contain file extensions. To store an object using a readable stream, call the [putStream()](docs/API.md#putstream) method. Similarly, to fetch a readable stream to a record, call the [getStream()](docs/API.md#getstream) method.
|
|
862
|
+
You can store and fetch binary records using [streams](https://nodejs.org/api/stream.html), so as to not load any content into memory. This can be used to manage extremely large files in a memory-limited environment. Note that the record content is treated as binary, so the keys *must* contain file extensions. To store an object using a readable stream, call the [putStream()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#putstream) method. Similarly, to fetch a readable stream to a record, call the [getStream()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#getstream) method.
|
|
847
863
|
|
|
848
864
|
Example of storing a record by spooling the data from a file:
|
|
849
865
|
|
|
850
866
|
```js
|
|
851
|
-
|
|
852
|
-
|
|
867
|
+
const fs = require('fs');
|
|
868
|
+
let stream = fs.createReadStream('picture.gif');
|
|
853
869
|
|
|
854
870
|
storage.putStream( 'test1.gif', stream, function(err) {
|
|
855
871
|
if (err) throw err;
|
|
@@ -859,8 +875,8 @@ storage.putStream( 'test1.gif', stream, function(err) {
|
|
|
859
875
|
Example of fetching a read stream and spooling it to a file:
|
|
860
876
|
|
|
861
877
|
```js
|
|
862
|
-
|
|
863
|
-
|
|
878
|
+
const fs = require('fs');
|
|
879
|
+
let writeStream = fs.createWriteStream('/let/tmp/downloaded.gif');
|
|
864
880
|
|
|
865
881
|
storage.getStream( 'test1.gif', function(err, readStream) {
|
|
866
882
|
if (err) throw err;
|
|
@@ -877,9 +893,9 @@ Please note that not all the storage engines support streams natively, so the co
|
|
|
877
893
|
|
|
878
894
|
By default all records live indefinitely, and have no predetermined lifespan. However, you can set an expiration date on any record, and it will be deleted on that day by the daily maintenance job (see [Daily Maintenance](#daily-maintenance) below). Note that there is no support for an expiration *time*, but rather only a date.
|
|
879
895
|
|
|
880
|
-
To set the expiration date for a record, call the [expire()](docs/API.md#expire) method, passing in the key and the desired expiration date. This function completes instantly and requires no callback. The date argument can be a JavaScript `Date` object, any supported date string (e.g. `YYYY-MM-DD`), or Epoch seconds. Example:
|
|
896
|
+
To set the expiration date for a record, call the [expire()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#expire) method, passing in the key and the desired expiration date. This function completes instantly and requires no callback. The date argument can be a JavaScript `Date` object, any supported date string (e.g. `YYYY-MM-DD`), or Epoch seconds. Example:
|
|
881
897
|
|
|
882
|
-
```
|
|
898
|
+
```js
|
|
883
899
|
storage.expire( 'test1', '2015-05-12' );
|
|
884
900
|
```
|
|
885
901
|
|
|
@@ -893,7 +909,7 @@ You can register custom record types if they require special handling for deleti
|
|
|
893
909
|
|
|
894
910
|
Your custom records are identified by a special top-level `type` property in their JSON. This property must be set to a unique string that you pre-register with the storage system at startup. Note that only JSON records are supported for custom deletion -- binary records are not.
|
|
895
911
|
|
|
896
|
-
To register a custom record type, call the [addRecordType()](docs/API.md#addrecordtype) method, and pass in a custom type key (string), and an object containing key/value pairs for actions and handlers. Currently only the `delete` action is defined, for handling maintenance (expiration) of your custom record type. Example use:
|
|
912
|
+
To register a custom record type, call the [addRecordType()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#addrecordtype) method, and pass in a custom type key (string), and an object containing key/value pairs for actions and handlers. Currently only the `delete` action is defined, for handling maintenance (expiration) of your custom record type. Example use:
|
|
897
913
|
|
|
898
914
|
```js
|
|
899
915
|
storage.addRecordType( 'my_custom_type', {
|
|
@@ -905,15 +921,15 @@ storage.addRecordType( 'my_custom_type', {
|
|
|
905
921
|
});
|
|
906
922
|
```
|
|
907
923
|
|
|
908
|
-
So the idea here is whenever the [daily maintenance](#daily-maintenance) job runs, and encounters JSON records with a `type` property set to `my_custom_type`, your custom handler function would be called to handle the deletes for the expired records. This would happen instead of a typical call to [delete()](docs/API.md#delete), which is the default behavior.
|
|
924
|
+
So the idea here is whenever the [daily maintenance](#daily-maintenance) job runs, and encounters JSON records with a `type` property set to `my_custom_type`, your custom handler function would be called to handle the deletes for the expired records. This would happen instead of a typical call to [delete()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#delete), which is the default behavior.
|
|
909
925
|
|
|
910
926
|
# Advisory Locking
|
|
911
927
|
|
|
912
|
-
The storage system provides a simple, in-memory advisory locking mechanism. All locks are based on a specified key, and can be exclusive or shared. You can also choose to wait for a lock to be released by passing `true` as the 2nd argument, or fail immediately if the key is already locked by passing `false`. To lock a key in exclusive mode, call [lock()](docs/API.md#lock), and to unlock it call [unlock()](docs/API.md#unlock).
|
|
928
|
+
The storage system provides a simple, in-memory advisory locking mechanism. All locks are based on a specified key, and can be exclusive or shared. You can also choose to wait for a lock to be released by passing `true` as the 2nd argument, or fail immediately if the key is already locked by passing `false`. To lock a key in exclusive mode, call [lock()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#lock), and to unlock it call [unlock()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#unlock).
|
|
913
929
|
|
|
914
930
|
Here is a simple use case:
|
|
915
931
|
|
|
916
|
-
```
|
|
932
|
+
```js
|
|
917
933
|
storage.lock( 'test1', true, function() {
|
|
918
934
|
// key is locked, now we can fetch
|
|
919
935
|
storage.get( key, function(err, data) {
|
|
@@ -941,7 +957,7 @@ storage.lock( 'test1', true, function() {
|
|
|
941
957
|
|
|
942
958
|
The above example is a typical counter increment pattern using advisory locks. The `test1` record is locked, fetched, its counter incremented, written back to disk, then finally unlocked. The idea is, even though all the storage operations are async, all other requests for this record will block until the lock is released. Remember that you always need to call `unlock()`, even if throwing an error.
|
|
943
959
|
|
|
944
|
-
In addition to exclusive locks, you can request a "shared" lock. Shared locking allows multiple clients to access the key simultaneously. For example, one could lock a key for reading using shared locks, but lock it for writing using an exclusive lock. To lock a key in shared mode, call [shareLock()](docs/API.md#sharelock), and to unlock it call [shareUnlock()](docs/API.md#shareunlock). Example:
|
|
960
|
+
In addition to exclusive locks, you can request a "shared" lock. Shared locking allows multiple clients to access the key simultaneously. For example, one could lock a key for reading using shared locks, but lock it for writing using an exclusive lock. To lock a key in shared mode, call [shareLock()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#sharelock), and to unlock it call [shareUnlock()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#shareunlock). Example:
|
|
945
961
|
|
|
946
962
|
```js
|
|
947
963
|
storage.shareLock( 'test1', true, function() {
|
|
@@ -1063,15 +1079,15 @@ Performance metrics are logged with the `category` column set to `perf`. The ac
|
|
|
1063
1079
|
[Storage][perf][second][Last Second Performance Metrics][{"get":{"min":0.132,"max":8.828,"total":319.99,"count":249,"avg":1.285},"index":{"min":24.361,"max":31.813,"total":137.421,"count":5,"avg":27.484},"commit":{"min":16.693,"max":26.227,"total":105.538,"count":5,"avg":21.107},"put":{"min":0.784,"max":7.367,"total":198.952,"count":125,"avg":1.591}}]
|
|
1064
1080
|
```
|
|
1065
1081
|
|
|
1066
|
-
That JSON data is the same format returned by the [getStats()](docs/API.md#getstats) method. See below for details.
|
|
1082
|
+
That JSON data is the same format returned by the [getStats()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#getstats) method. See below for details.
|
|
1067
1083
|
|
|
1068
1084
|
Note that performance metrics are only logged if there was at least one event. If your application is completely idle, it will not log anything.
|
|
1069
1085
|
|
|
1070
1086
|
# Performance Metrics
|
|
1071
1087
|
|
|
1072
|
-
If you want to fetch performance metrics on-demand, call the [getStats()](docs/API.md#getstats) method. This returns an object containing a plethora of information, including min/avg/max metrics for all events. Example response, formatted as JSON for display:
|
|
1088
|
+
If you want to fetch performance metrics on-demand, call the [getStats()](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/API.md#getstats) method. This returns an object containing a plethora of information, including min/avg/max metrics for all events. Example response, formatted as JSON for display:
|
|
1073
1089
|
|
|
1074
|
-
```
|
|
1090
|
+
```json
|
|
1075
1091
|
{
|
|
1076
1092
|
"version": "2.0.0",
|
|
1077
1093
|
"engine": "Filesystem",
|
|
@@ -1125,7 +1141,7 @@ Here are descriptions of the main elements:
|
|
|
1125
1141
|
| `version` | The current version of the `pixl-server-storage` module. |
|
|
1126
1142
|
| `engine` | The name of the current engine Plugin, e.g. `Filesystem`. |
|
|
1127
1143
|
| `concurrency` | The current concurrency setting (i.e. max threads). |
|
|
1128
|
-
| `transactions` | Whether [transactions](docs/Transactions.md) are enabled (true) or disabled (false). |
|
|
1144
|
+
| `transactions` | Whether [transactions](https://github.com/jhuckaby/pixl-server-storage/blob/master/docs/Transactions.md) are enabled (true) or disabled (false). |
|
|
1129
1145
|
| `last_second` | A performance summary of the last second (see below). |
|
|
1130
1146
|
| `last_minute` | A performance summary of the last minute (see below). |
|
|
1131
1147
|
| `recent_events` | The most recent N events (see below). |
|
|
@@ -1133,7 +1149,7 @@ Here are descriptions of the main elements:
|
|
|
1133
1149
|
|
|
1134
1150
|
The performance metrics (both `last_second` and `last_minute`) include minimums, averages, maximums, counts and totals for each event, and are provided in this format:
|
|
1135
1151
|
|
|
1136
|
-
```
|
|
1152
|
+
```json
|
|
1137
1153
|
{
|
|
1138
1154
|
"search": {
|
|
1139
1155
|
"min": 14.306,
|
|
@@ -1160,7 +1176,7 @@ The `recent_events` object will only be populated if the `max_recent_events` con
|
|
|
1160
1176
|
|
|
1161
1177
|
If you plan on expiring records for future deletion (see [Expiring Data](#expiring-data) above), you should enable the nightly maintenance job. This will iterate over all the records that expired on the current day, and actually delete them. To do this, set the [maintenance](#maintenance) key in your storage configuration, and set it to a `HH::MM` string:
|
|
1162
1178
|
|
|
1163
|
-
```
|
|
1179
|
+
```js
|
|
1164
1180
|
{
|
|
1165
1181
|
"maintenance": "04:30" // run daily at 4:30 AM
|
|
1166
1182
|
}
|
|
@@ -1183,72 +1199,68 @@ Here are the API methods your class should define:
|
|
|
1183
1199
|
| `delete()` | KEY, CALLBACK | Delete the specified key, then fire the callback. |
|
|
1184
1200
|
| `shutdown()` | CALLBACK | Optional, called as the server shuts down. Fire the callback when your engine has stopped. |
|
|
1185
1201
|
|
|
1186
|
-
It is recommended you
|
|
1202
|
+
It is recommended you inherit from the `pixl-server/component` base class. This implements some useful methods such as `logDebug()`.
|
|
1187
1203
|
|
|
1188
1204
|
Here is an example skeleton class you can start from:
|
|
1189
1205
|
|
|
1190
|
-
```
|
|
1191
|
-
|
|
1192
|
-
var Component = require("pixl-server/component");
|
|
1206
|
+
```js
|
|
1207
|
+
const Component = require("pixl-server/component");
|
|
1193
1208
|
|
|
1194
|
-
module.exports =
|
|
1195
|
-
|
|
1196
|
-
__name: 'MyEngine',
|
|
1197
|
-
__parent: Component,
|
|
1209
|
+
module.exports = class MyEngine extends Component {
|
|
1198
1210
|
|
|
1199
|
-
startup
|
|
1211
|
+
startup(callback) {
|
|
1200
1212
|
// setup initial connection
|
|
1201
|
-
|
|
1213
|
+
let self = this;
|
|
1202
1214
|
this.logDebug(2, "Setting up MyEngine");
|
|
1203
1215
|
callback();
|
|
1204
|
-
}
|
|
1216
|
+
}
|
|
1205
1217
|
|
|
1206
|
-
put
|
|
1218
|
+
put(key, value, callback) {
|
|
1207
1219
|
// store record given key and value
|
|
1208
1220
|
callback();
|
|
1209
|
-
}
|
|
1221
|
+
}
|
|
1210
1222
|
|
|
1211
|
-
head
|
|
1223
|
+
head(key, callback) {
|
|
1212
1224
|
// retrieve metadata on record (mod, len)
|
|
1213
1225
|
callback();
|
|
1214
|
-
}
|
|
1226
|
+
}
|
|
1215
1227
|
|
|
1216
|
-
get
|
|
1228
|
+
get(key, callback) {
|
|
1217
1229
|
// fetch record value given key
|
|
1218
1230
|
callback();
|
|
1219
|
-
}
|
|
1231
|
+
}
|
|
1220
1232
|
|
|
1221
|
-
delete
|
|
1233
|
+
delete(key, callback) {
|
|
1222
1234
|
// delete record
|
|
1223
1235
|
callback();
|
|
1224
|
-
}
|
|
1236
|
+
}
|
|
1225
1237
|
|
|
1226
|
-
shutdown
|
|
1238
|
+
shutdown(callback) {
|
|
1227
1239
|
// shutdown storage
|
|
1228
1240
|
this.logDebug(2, "Shutting down MyEngine");
|
|
1229
1241
|
callback();
|
|
1230
1242
|
}
|
|
1231
1243
|
|
|
1232
|
-
}
|
|
1244
|
+
};
|
|
1233
1245
|
```
|
|
1234
1246
|
|
|
1235
1247
|
# Unit Tests
|
|
1236
1248
|
|
|
1237
1249
|
To run the unit test suite, issue this command from within the module directory:
|
|
1238
1250
|
|
|
1239
|
-
```
|
|
1251
|
+
```sh
|
|
1240
1252
|
npm test
|
|
1241
1253
|
```
|
|
1242
1254
|
|
|
1243
|
-
If you install the [pixl-unit](https://www.
|
|
1255
|
+
If you install the [pixl-unit](https://www.github.com/jhuckaby/pixl-unit) module globally, you can provide various command-line options, such as verbose mode:
|
|
1244
1256
|
|
|
1245
|
-
```
|
|
1257
|
+
```sh
|
|
1246
1258
|
pixl-unit test/test.js --verbose
|
|
1247
1259
|
```
|
|
1248
1260
|
|
|
1249
1261
|
This also allows you to specify an alternate test configuration file via the `--configFile` option. Using this you can load your own test config, which may use a different engine (e.g. S3, Couchbase, etc.):
|
|
1250
1262
|
|
|
1251
|
-
```
|
|
1263
|
+
```sh
|
|
1252
1264
|
pixl-unit test/test.js --configFile /path/to/my/config.json
|
|
1253
1265
|
```
|
|
1254
1266
|
|