1
1
#!/usr/bin/env node
2
2
3
- let args = process . argv . slice ( 2 ) ;
4
- /*
5
- let host = args.host || 'localhost';
6
- let port = parseInt(args.port || 3000);
7
- let user = args.user || undefined;
8
- let pass = args.pass || undefined;
9
- */
10
- let client = require ( './client' ) ;
11
-
12
- /*
13
- function onerror(error) {
14
- console.log({ db_error: error });
15
- }
16
- */
3
+ const env = process . env ;
4
+ const args = process . argv . slice ( 2 ) ;
5
+ const client = require ( './client' ) ;
6
+ const { log } = require ( './util' ) ;
17
7
18
- console . log ( '[net-level-clone]' ) ;
19
8
if ( args . length < 2 ) {
20
9
console . log ( 'usage: host/port/user/pass/base host/port/user/pass/base query' ) ;
21
10
process . exit ( ) ;
@@ -32,56 +21,99 @@ function parse(tok) {
32
21
} ;
33
22
}
34
23
35
- function connect ( rec ) {
36
- return new Promise ( ( resolve , reject ) => {
37
- let db = new client ( ) ;
38
- db . open ( rec . host , rec . port )
39
- . then ( ( ) => {
40
- return db . auth ( rec . user , rec . pass ) ;
41
- } )
42
- . then ( ( ) => {
43
- return db . use ( rec . base ) ;
44
- } )
45
- . then ( ( ) => {
46
- console . log ( rec ) ;
47
- resolve ( db ) ;
48
- } )
49
- . catch ( reject ) ;
50
- } ) ;
24
+ const retries = parseInt ( env [ 'RETRIES' ] || 60 ) ;
25
+ const retry_timeout = parseInt ( env [ 'RETRY_TIMEOUT' ] || 1 ) * 1000 ;
26
+
27
+ async function connect ( rec ) {
28
+ const db = new client ( { retries, retry_timeout } ) ;
29
+ await db . open ( rec . host , rec . port ) ;
30
+ await db . auth ( rec . user , rec . pass ) ;
31
+ await db . use ( rec . base ) ;
32
+ return db ;
51
33
}
52
- let b1 = parse ( args [ 0 ] ) ;
53
- let b2 = parse ( args [ 1 ] ) ;
54
- let q = eval ( `(${ args [ 2 ] || '{}' } )` ) ;
55
- let clone = b1 . host !== b2 . host || b1 . base !== b2 . base ;
56
-
57
- connect ( b1 )
58
- . then ( ( db ) => {
59
- b1 = db ;
60
- return connect ( b2 ) ;
61
- } )
62
- . then ( ( db ) => {
63
- b2 = db ;
64
- } )
65
- . then ( ( ) => {
66
- b1 . list ( q , ( key , value ) => {
67
- console . log ( { key, value } ) ;
68
- if ( clone && key && value ) {
69
- b2 . put ( key , value )
34
+
35
+ // for use in mode settings eval
36
+ const series = 1 ;
37
+ const b1t = parse ( args [ 0 ] ) ;
38
+ const b2t = parse ( args [ 1 ] ) ;
39
+ const q = eval ( `(${ args [ 2 ] || '{}' } )` ) ;
40
+ const can_clone = b1t . host !== b2t . host || b1t . port !== b2t . port || b1t . base !== b2t . base ;
41
+
42
+ const interval = parseInt ( q . interval || 0 ) * 1000 ;
43
+ const overlap = q . overlap ;
44
+ const mode = q . mode ;
45
+
46
+ delete q . interval ;
47
+ delete q . overlap ;
48
+ delete q . mode ;
49
+
50
+ log ( '[net-level-clone]' , [ b1t . host , b1t . port , b1t . base ] , [ b2t . host , b2t . port , b2t . base ] ) ;
51
+
52
+ async function do_clone ( b1 , b2 ) {
53
+ // (time) series continues after last key from destination base
54
+ // with the option to include that record again with overlap:true
55
+ // which is useful when the last record will be updated several times
56
+ // before being finalized and the next record written (streaming + historical)
57
+ if ( mode === series ) {
58
+ const lastkey = await b2 . list ( { reverse : true , limit : 1 , values : false } ) ;
59
+ if ( lastkey && lastkey . length ) {
60
+ log ( { lastkey : lastkey [ 0 ] . key } ) ;
61
+ if ( overlap ) {
62
+ q . gte = lastkey [ 0 ] . key ;
63
+ } else {
64
+ q . gt = lastkey [ 0 ] . key ;
65
+ }
66
+ }
67
+ }
68
+
69
+ const pro = [ ] ;
70
+
71
+ q . limit = 500 ;
72
+ let cloned ;
73
+ do {
74
+ cloned = 0 ;
75
+ await b1 . list ( q , ( key , value ) => {
76
+ log ( { get : key } ) ;
77
+ if ( key && value ) {
78
+ pro . push ( b2 . put ( key , value )
70
79
. then ( ( ) => {
71
- console . log ( { put : key } ) ;
80
+ cloned ++ ;
81
+ if ( overlap ) {
82
+ q . gte = key ;
83
+ } else {
84
+ q . gt = key ;
85
+ }
86
+ log ( { put : key } ) ;
72
87
} )
73
88
. catch ( ( /*error*/ ) => {
74
- console . log ( { put_error : key } ) ;
89
+ log ( { put_error : key } ) ;
75
90
b1 . close ( ) ;
76
- } ) ;
91
+ } )
92
+ ) ;
77
93
}
78
- } )
79
- . then ( ( ) => {
80
- b1 . close ( ) ;
81
- b2 . close ( ) ;
82
- process . exit ( ) ;
83
- } )
84
- . catch ( ( error ) => {
85
- console . log ( error ) ;
86
- } ) ;
87
- } ) ;
94
+ } ) ;
95
+ await Promise . all ( pro ) ;
96
+ console . log ( { cloned } ) ;
97
+ } while ( cloned > 0 ) ;
98
+
99
+ }
100
+
101
+ if ( can_clone ) ( async ( ) => {
102
+ const b1 = await connect ( b1t ) ;
103
+ const b2 = await connect ( b2t ) ;
104
+
105
+ while ( true ) {
106
+ await do_clone ( b1 , b2 ) ;
107
+ if ( interval ) {
108
+ await new Promise ( resolve => setTimeout ( resolve , interval ) ) ;
109
+ continue ;
110
+ } else {
111
+ break ;
112
+ }
113
+ }
114
+
115
+ await b1 . close ( ) ;
116
+ await b2 . close ( ) ;
117
+ process . exit ( ) ;
118
+
119
+ } ) ( ) ;
0 commit comments