pixl-server-storage 3.1.17 → 3.2.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Overview
2
2
 
3
- This module is a component for use in [pixl-server](https://www.npmjs.com/package/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.
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
- ```javascript
96
- var PixlServer = require('pixl-server');
97
- var server = new PixlServer({
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": "/var/log",
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": "/var/data/myserver",
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
- var storage = server.Storage;
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.npmjs.com/package/pixl-server) parent module, and then specifying [pixl-server-storage](https://www.npmjs.com/package/pixl-server-storage) as a component:
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
- ```javascript
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 `/var/data/myserver` as a base directory. It then simply stores a test key, then fetches it back.
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.npmjs.com/package/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:
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
- ```javascript
152
- var StandaloneStorage = require('pixl-server-storage/standalone');
151
+ ```js
152
+ const StandaloneStorage = require('pixl-server-storage/standalone');
153
153
 
154
- var config = {
154
+ const config = {
155
155
  "engine": "Filesystem",
156
156
  "Filesystem": {
157
- "base_dir": "/var/data/myserver"
157
+ "base_dir": "/let/data/myserver"
158
158
  }
159
159
  };
160
160
 
161
- var storage = new StandaloneStorage(config, function(err) {
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.npmjs.com/package/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.
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
- ```javascript
192
+ ```json
193
193
  {
194
194
  "engine": "Filesystem",
195
195
  "Filesystem": {
196
- "base_dir": "/var/data/myserver"
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
- ```javascript
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
- ```javascript
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
- ```javascript
288
+ ```json
289
289
  {
290
290
  "engine": "Filesystem",
291
291
  "Filesystem": {
292
- "base_dir": "/var/data/myserver"
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
- /var/data/myserver/5a/10/5e/5a105e8b9d40e1329780d62ea2265d8a.json
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
- ```javascript
309
+ ```json
310
310
  {
311
311
  "engine": "Filesystem",
312
312
  "Filesystem": {
313
- "base_dir": "/var/data/myserver",
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 `/var/data/myserver`:
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
- /var/data/myserver/users/01/9a/aa/019aaa6887e5ce3533dcc691b05e69e4.json
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
- ```javascript
344
+ ```json
345
345
  {
346
346
  "engine": "Filesystem",
347
347
  "Filesystem": {
348
- "base_dir": "/var/data/myserver",
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
- /var/data/myserver/users/jhuckaby.json
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
- ```javascript
368
+ ```json
369
369
  {
370
370
  "engine": "Filesystem",
371
371
  "Filesystem": {
372
- "base_dir": "/var/data/myserver",
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
- ```js
392
+ ```json
393
393
  {
394
394
  "engine": "Filesystem",
395
395
  "Filesystem": {
396
- "base_dir": "/var/data/myserver",
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
- ```javascript
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
- ```js
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
- ```js
498
- "cache": {
499
- "enabled": true,
500
- "maxItems": 1000,
501
- "maxBytes": 10485760
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
- ```javascript
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 [redis](https://www.npmjs.com/package/redis) module into your app:
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 redis
563
+ ```sh
564
+ npm install --save ioredis
563
565
  ```
564
566
 
565
567
  Then configure your storage thusly:
566
568
 
567
- ```javascript
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 Properties](https://github.com/NodeRedis/node_redis#options-object-properties) for other things you can include here, such as authentication and database selection.
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 two modules into your app:
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 ioredis-timeout
591
+ ```sh
592
+ npm install --save ioredis
590
593
  ```
591
594
 
592
595
  Then configure your storage thusly:
593
596
 
594
- ```javascript
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. Set the `timeout` to the desired operation timeout in milliseconds (it defaults to `1000`). The `connectRetries` sets the number of retries on the initial socket connect operation (it defaults to `5`).
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
- The `clusterOpts` property can hold several different cluster configuration options. Please see the [ioredis API docs](https://github.com/luin/ioredis/blob/master/API.md#new-redisport-host-options) for other things you can include here, such as authentication and database selection. 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)).
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
- ```javascript
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) and [cache_size](https://www.sqlite.org/pragma.html#pragma_cache_size), among many others.
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": "/var/data/myserver"
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
- ```javascript
724
- var storage = server.Storage;
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
- ```javascript
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
- ```javascript
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
- ```javascript
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
- ```javascript
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
- ```javascript
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
- ```javascript
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
- ```javascript
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
- ```javascript
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
- ```javascript
827
- var fs = require('fs');
828
- var buffer = fs.readFileSync('picture.gif');
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
- ```javascript
837
- var fs = require('fs');
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
- var fs = require('fs');
852
- var stream = fs.createReadStream('picture.gif');
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
- var fs = require('fs');
863
- var writeStream = fs.createWriteStream('/var/tmp/downloaded.gif');
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
- ```javascript
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
- ```javascript
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
- ```js
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
- ```js
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
- ```javascript
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 use the [pixl-class](https://www.npmjs.com/package/pixl-class) class framework, and inherit from the `pixl-server/component` base class. This implements some useful methods such as `logDebug()`.
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
- ```javascript
1191
- var Class = require("pixl-class");
1192
- var Component = require("pixl-server/component");
1206
+ ```js
1207
+ const Component = require("pixl-server/component");
1193
1208
 
1194
- module.exports = Class.create({
1195
-
1196
- __name: 'MyEngine',
1197
- __parent: Component,
1209
+ module.exports = class MyEngine extends Component {
1198
1210
 
1199
- startup: function(callback) {
1211
+ startup(callback) {
1200
1212
  // setup initial connection
1201
- var self = this;
1213
+ let self = this;
1202
1214
  this.logDebug(2, "Setting up MyEngine");
1203
1215
  callback();
1204
- },
1216
+ }
1205
1217
 
1206
- put: function(key, value, callback) {
1218
+ put(key, value, callback) {
1207
1219
  // store record given key and value
1208
1220
  callback();
1209
- },
1221
+ }
1210
1222
 
1211
- head: function(key, callback) {
1223
+ head(key, callback) {
1212
1224
  // retrieve metadata on record (mod, len)
1213
1225
  callback();
1214
- },
1226
+ }
1215
1227
 
1216
- get: function(key, callback) {
1228
+ get(key, callback) {
1217
1229
  // fetch record value given key
1218
1230
  callback();
1219
- },
1231
+ }
1220
1232
 
1221
- delete: function(key, callback) {
1233
+ delete(key, callback) {
1222
1234
  // delete record
1223
1235
  callback();
1224
- },
1236
+ }
1225
1237
 
1226
- shutdown: function(callback) {
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.npmjs.com/package/pixl-unit) module globally, you can provide various command-line options, such as verbose mode:
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