Skip to content

Commit d770c10

Browse files
committed
Switch to allow table overwrite during restore. CLI examples added to readme.
1 parent 6daf8f1 commit d770c10

File tree

3 files changed

+79
-23
lines changed

3 files changed

+79
-23
lines changed

README.md

Lines changed: 46 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ __Arguments__
161161

162162
It is suitable for restoring large tables without needing to write to disk or use a large amount of memory. Use it on an AWS EC2 instance for best results and to minimise network latency, this should yield restore speeds of around 15min per GB.
163163

164+
Use `--overwrite` if the table already exists. Otherwise it will attempt to generate table on the fly.
165+
164166
Can be run as a command line script or as an npm module.
165167

166168
# Command line usage
@@ -174,17 +176,54 @@ Can be run as a command line script or as an npm module.
174176
-V, --version output the version number
175177
-s, --source [path] Full S3 path to a JSON backup file (Required)
176178
-t, --table [name] Name of the Dynamo Table to restore to (Required)
179+
-o, --overwrite Table already exists, skip auto-create. Default is false.
177180
-c, --concurrency <requestcount> Number of concurrent requests & dynamo capacity units. Defaults to 200.
178181
-pk, --partitionkey [columnname] Name of Primary Partition Key. If not provided will try determine from backup.
179182
-sk, --sortkey [columnname] Name of Secondary Sort Key. Ignored unless --partitionkey is provided.
180183
-rc, --readcapacity <units> Read Units for new table (when finished). Default is 5.
181-
-wc, --writecapacity <units> Write Units for new table (when finished). Default is 5.
182-
-sf, --stop-on-failure Stop process when the same batch fails to restore 3 times. Defaults to false.
184+
-wc, --writecapacity <units> Write Units for new table (when finished). Default is --concurrency.
185+
-sf, --stop-on-failure Stop process when the same batch fails to restore multiple times. Defaults to false.
183186
--aws-key <key> AWS access key. Will use AWS_ACCESS_KEY_ID env var if --aws-key not set
184187
--aws-secret <secret> AWS secret key. Will use AWS_SECRET_ACCESS_KEY env var if --aws-secret not set
185188
--aws-region <region> AWS region. Will use AWS_DEFAULT_REGION env var if --aws-region not set
186189
```
187190

191+
## Examples
192+
193+
```
194+
195+
# Restore over existing table (cmd.exe).
196+
> node ./bin/dynamo-restore-from-s3 -t acme-customers -s s3://my-backups/acme-customers.json --overwrite
197+
198+
# Restore over existing table (shell).
199+
$ ./bin/dynamo-restore-from-s3 -t acme-customers -s s3://my-backups/acme-customers.json --overwrite
200+
201+
# Restore over existing table, 1000 concurrent requests. Stop if any batch fails 1000 times.
202+
$ ./bin/dynamo-restore-from-s3 -t acme-customers -c 1000 -s s3://my-backups/acme-customers.json --overwrite -sf
203+
204+
# Restore over existing table, 1000 concurrent requests. When finished, set read capacity to 50 and write capacity to 10 (both needed).
205+
$ ./bin/dynamo-restore-from-s3 -t acme-customers -c 1000 -s s3://my-backups/acme-customers.json --overwrite --readcapacity 50 --writecapacity 10
206+
207+
# Auto-generate table (determine PK from backup).
208+
$ ./bin/dynamo-restore-from-s3 -t acme-customers -s s3://my-backups/acme-customers.json
209+
210+
# Auto-generate table with partition and sort key.
211+
$ ./bin/dynamo-restore-from-s3 -t acme-orders -s s3://my-backups/acme-orders.json -pk customerId -sk createDate
212+
213+
# Auto-generate table, defined PK. Concurrency 2000 (~ 2GB backup).
214+
$ ./bin/dynamo-restore-from-s3 -t acme-orders -pk orderId -c 2000 -s s3://my-backups/acme-orders.json
215+
216+
# Auto-generate table. 2000 write units during restore. When finished set 50 write units and 100 write units (both needed).
217+
$ ./bin/dynamo-restore-from-s3 -t acme-orders -c 2000 -s s3://my-backups/acme-orders.json --readcapacity 100 --writecapacity 50
218+
219+
# Auto-generate table. Concurrency 50 (10 MB backup or less).
220+
$ ./bin/dynamo-restore-from-s3 -t acme-orders -c 50 -s s3://my-backups/acme-orders.json
221+
222+
# Auto-generate table. Concurrency 50. Stop process if any batch fails 50 times.
223+
$ ./bin/dynamo-restore-from-s3 -t acme-orders -c 50 -sf -s s3://my-backups/acme-orders.json
224+
225+
```
226+
188227
# npm module usage
189228

190229
## Quick Example
@@ -195,10 +234,8 @@ var DynamoRestore = require('dynamo-backup-to-s3').Restore;
195234
var restore = new DynamoRestore({
196235
source: 's3://my-backups/DynamoDB-backup-2016-09-28-15-36-40/acme-customers-prod.json',
197236
table: 'acme-customers-dev',
237+
overwrite: true,
198238
concurrency: 200, // for large restores use 1 unit per MB as a rule of thumb (ie 1000 for 1GB restore)
199-
partitionkey: 'customerId',
200-
readcapacity: 1,
201-
writecapacity: 1,
202239
awsAccessKey: /* AWS access key */,
203240
awsSecretKey: /* AWS secret key */,
204241
awsRegion: /* AWS region */
@@ -228,11 +265,12 @@ restore.run(function() {
228265
```
229266
var options = {
230267
source: /* path to json file in s3 bucket, should start with s3://bucketname/... */,
231-
table: /* name of dynamo table, created on the fly, MUST NOT EXIST */,
268+
table: /* name of dynamo table, will be created on the fly unless overwritten */,
269+
overwrite: /* true/false if table already exits (defaults to false) */
232270
concurrency: /* number of concurrent requests (and dynamo write capacity units) */,
233-
partitionkey: /* name of partition key column*/,
271+
partitionkey: /* name of partition key column */,
234272
sortkey: /* name of secondary (sort) key column */ ,
235-
readcapacity: /* number of read capacity units */,
273+
readcapacity: /* number of read capacity units (when restore finishes) */,
236274
writecapacity: /* number of write capacity units (when restore finishes) */,
237275
stopOnFailure: /* true/false should a single failed batch stop the whole restore job? */,
238276
awsAccessKey: /* AWS access key */,

bin/dynamo-restore-from-s3

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ program
99
.usage('[options] -s "s3://mybucket/path/to/file.json" -t "new-dynamodb-table"')
1010
.option('-s, --source [path]', 'Full S3 path to a JSON backup file (Required)')
1111
.option('-t, --table [name]', 'Name of the Dynamo Table to restore to (Required)')
12+
.option('-o, --overwrite', 'Table already exists, skip auto-create. Default is false.')
1213
.option('-c, --concurrency <requestcount>', 'Number of concurrent requests & dynamo capacity units. Defaults to 200.')
1314
.option('-pk, --partitionkey [columnname]', 'Name of Primary Partition Key. If not provided will try determine from backup.')
1415
.option('-sk, --sortkey [columnname]', 'Name of Secondary Sort Key. Ignored unless --partitionkey is provided.')
1516
.option('-rc, --readcapacity <units>', 'Read Units for new table (when finished). Default is 5.')
16-
.option('-wc, --writecapacity <units>', 'Write Units for new table (when finished). Default is 5.')
17+
.option('-wc, --writecapacity <units>', 'Write Units for new table (when finished). Default is --concurrency.')
1718
.option('-sf, --stop-on-failure', 'Stop process when the same batch fails to restore 3 times. Defaults to false.', true)
1819
.option('--aws-key <key>', 'AWS access key. Will use AWS_ACCESS_KEY_ID env var if --aws-key not set')
1920
.option('--aws-secret <secret>', 'AWS secret key. Will use AWS_SECRET_ACCESS_KEY env var if --aws-secret not set')
@@ -36,6 +37,7 @@ var dynamoRestore = new DynamoRestore({
3637
// Main settings
3738
source: program.source,
3839
table: program.table,
40+
overwrite: !!program.overwrite,
3941
concurrency: program.concurrency,
4042
stopOnFailure: !!program.stopOnFailure,
4143
// New table properties
@@ -64,6 +66,10 @@ dynamoRestore.on('error', function(message) {
6466
process.exit(-1);
6567
});
6668

69+
dynamoRestore.on('warning', function(message) {
70+
console.log(message);
71+
});
72+
6773
dynamoRestore.on('start-download', function(streamMeta) {
6874
var time = runTimes.startDownload = new Date().getTime();
6975
console.log('Starting download. %s remaining...', translate(streamMeta.ContentLength));

lib/dynamo-restore.js

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ function DynamoRestore(options) {
1919
options.minConcurrency = 1;
2020
options.maxConcurrency = options.concurrency;
2121
options.readcapacity = options.readcapacity || 5;
22-
options.writecapacity = options.writecapacity || 5;
22+
options.writecapacity = options.writecapacity || 0;
2323
options.stopOnFailure = options.stopOnFailure || false;
2424
options.awsKey = options.awsKey || process.env.AWS_ACCESS_KEY_ID;
2525
options.awsSecret = options.awsSecret || process.env.AWS_SECRET_ACCESS_KEY;
@@ -42,18 +42,6 @@ DynamoRestore.prototype.run = function(finishCallback) {
4242
this._validateS3Backup(this.options);
4343
this._validateTable(this.options);
4444
this._startDownload();
45-
this.on('finish', (function() {
46-
var dynamodb = new AWS.DynamoDB(),
47-
options = this.options;
48-
// Finish off by updating read/write capacity to end-state
49-
dynamodb.updateTable({
50-
TableName: options.table,
51-
ProvisionedThroughput: {
52-
ReadCapacityUnits: options.readcapacity,
53-
WriteCapacityUnits: options.writecapacity
54-
}
55-
}, finishCallback);
56-
}).bind(this));
5745
// Exit program by default if there are no error listeners attached.
5846
this.on('error', (function(message) {
5947
if (finishCallback) {
@@ -63,6 +51,23 @@ DynamoRestore.prototype.run = function(finishCallback) {
6351
throw new Error(message);
6452
}
6553
}).bind(this));
54+
// Finish off by updating write capacity to end-state (if needed)
55+
this.on('finish', (function() {
56+
var dynamodb = new AWS.DynamoDB(),
57+
options = this.options;
58+
// Do we need to update write capacity?
59+
if (options.writecapacity) {
60+
dynamodb.updateTable({
61+
TableName: options.table,
62+
ProvisionedThroughput: {
63+
ReadCapacityUnits: options.readcapacity,
64+
WriteCapacityUnits: options.writecapacity
65+
}
66+
}, finishCallback);
67+
} else {
68+
finishCallback();
69+
}
70+
}).bind(this));
6671
};
6772

6873
DynamoRestore.prototype._validateS3Backup = function(options) {
@@ -96,7 +101,14 @@ DynamoRestore.prototype._checkTableExists = function(error, data) {
96101
return this.emit('error', 'Fatal Error. Could not connect to AWS DynamoDB engine. Please check your credentials.');
97102
}
98103
if (data.TableNames.indexOf(this.options.table) > -1) {
99-
return this.emit('error', 'Fatal Error. The destination table already exists! Exiting process..');
104+
// Table exists, should we overwrite it??
105+
if (this.options.overwrite) {
106+
this.emit('warning', util.format('WARN: table [%s] will be overwritten.', options.table));
107+
dynamodb.describeTable({ TableName: this.options.table }, this._checkTableReady.bind(this));
108+
} else {
109+
this.emit('error', 'Fatal Error. The destination table already exists! Exiting process..');
110+
}
111+
return;
100112
}
101113
if (this.options.partitionkey && this.options.partitionkeytype) {
102114
// Once we know the partition key and data type the rest is a breeze.

0 commit comments

Comments
 (0)