@cloudant/couchbackup 2.7.1-SNAPSHOT.56 → 2.8.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/CHANGES.md CHANGED
@@ -1,9 +1,12 @@
1
- # Unreleased
1
+ # 2.8.0 (2021-11-25)
2
2
  - [FIXED] Corrected `user-agent` header on requests.
3
3
  - [FIXED] Restore of shallow backups created with versions <=2.4.2.
4
4
  - [IMPROVED] Added quiet option to backup and restore to suppress batch messages.
5
5
  - [IMPROVED] Added a preflight check for restore function to make sure that a target database is new and empty.
6
6
  - [IMPROVED] Added handling for errors reading log file.
7
+ - [IMPROVED] Split changes spooling to improve reliability on databases with
8
+ millions of documents.
9
+ - [UPGRADED] `@ibm-cloud/cloudant`, `commander` and `debug` dependencies.
7
10
 
8
11
  # 2.7.0 (2021-09-14)
9
12
  - [UPGRADED] Cloudant client dependency from `@cloudant/cloudant` to `@ibm-cloud/cloudant`.
package/README.md CHANGED
@@ -35,7 +35,7 @@ npm install -g @cloudant/couchbackup
35
35
  ```
36
36
 
37
37
  ### Requirements
38
- * The minimum required Node.js version is 10.
38
+ * The minimum required Node.js version is 12.
39
39
  * The minimum required CouchDB version is 2.0.0.
40
40
 
41
41
  ### Snapshots
@@ -34,6 +34,9 @@ module.exports = function(db, log, bufferSize, ee, callback) {
34
34
  let batch = 0;
35
35
  let lastSeq = null;
36
36
  const logStream = fs.createWriteStream(log);
37
+ let pending = 0;
38
+ // The number of changes to fetch per request
39
+ const limit = 100000;
37
40
 
38
41
  // send documents ids to the queue in batches of bufferSize + the last batch
39
42
  const processBuffer = function(lastOne) {
@@ -57,36 +60,52 @@ module.exports = function(db, log, bufferSize, ee, callback) {
57
60
  processBuffer(false);
58
61
  } else if (c.last_seq) {
59
62
  lastSeq = c.last_seq;
63
+ pending = c.pending;
60
64
  }
61
65
  }
62
66
  };
63
67
 
64
- // stream the changes feed to disk
65
- db.service.postChangesAsStream({ db: db.db, seq_interval: 10000 }).then(response => {
66
- response.result.pipe(liner())
67
- .on('error', function(err) {
68
- callback(err);
68
+ function getChanges(since = 0) {
69
+ debug('making changes request since ' + since);
70
+ return db.service.postChangesAsStream({ db: db.db, since: since, limit: limit, seq_interval: limit })
71
+ .then(response => {
72
+ response.result.pipe(liner())
73
+ .on('error', function(err) {
74
+ logStream.end();
75
+ callback(err);
76
+ })
77
+ .pipe(change(onChange))
78
+ .on('error', function(err) {
79
+ logStream.end();
80
+ callback(err);
81
+ })
82
+ .on('finish', function() {
83
+ processBuffer(true);
84
+ if (!lastSeq) {
85
+ logStream.end();
86
+ debug('changes request terminated before last_seq was sent');
87
+ callback(new error.BackupError('SpoolChangesError', 'Changes request terminated before last_seq was sent'));
88
+ } else {
89
+ debug(`changes request completed with last_seq: ${lastSeq} and ${pending} changes pending.`);
90
+ if (pending > 0) {
91
+ // Return the next promise
92
+ return getChanges(lastSeq);
93
+ } else {
94
+ debug('finished streaming database changes');
95
+ logStream.end(':changes_complete ' + lastSeq + '\n', 'utf8', callback);
96
+ }
97
+ }
98
+ });
69
99
  })
70
- .pipe(change(onChange))
71
- .on('error', function(err) {
72
- callback(err);
73
- })
74
- .on('finish', function() {
75
- processBuffer(true);
76
- if (!lastSeq) {
77
- logStream.end();
78
- debug('changes request terminated before last_seq was sent');
79
- callback(new error.BackupError('SpoolChangesError', 'Changes request terminated before last_seq was sent'));
80
- } else {
81
- debug('finished streaming database changes');
82
- logStream.end(':changes_complete ' + lastSeq + '\n', 'utf8', callback);
100
+ .catch(err => {
101
+ logStream.end();
102
+ if (err.status && err.status >= 400) {
103
+ callback(error.convertResponseError(err));
104
+ } else if (err.name !== 'SpoolChangesError') {
105
+ callback(new error.BackupError('SpoolChangesError', `Failed changes request - ${err.message}`));
83
106
  }
84
107
  });
85
- }).catch(err => {
86
- if (err.status && err.status >= 400) {
87
- callback(error.convertResponseError(err));
88
- } else {
89
- callback(new error.BackupError('SpoolChangesError', `Failed changes request - ${err.message}`));
90
- }
91
- });
108
+ }
109
+
110
+ getChanges();
92
111
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudant/couchbackup",
3
- "version": "2.7.1-SNAPSHOT.56",
3
+ "version": "2.8.0",
4
4
  "description": "CouchBackup - command-line backup utility for Cloudant/CouchDB",
5
5
  "homepage": "https://github.com/cloudant/couchbackup",
6
6
  "repository": "https://github.com/cloudant/couchbackup.git",