11#!/usr/bin/env node
22
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' ) ;
177
18- console . log ( '[net-level-clone]' ) ;
198if ( args . length < 2 ) {
209 console . log ( 'usage: host/port/user/pass/base host/port/user/pass/base query' ) ;
2110 process . exit ( ) ;
@@ -32,56 +21,99 @@ function parse(tok) {
3221 } ;
3322}
3423
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 ;
5133}
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 )
7079 . 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 } ) ;
7287 } )
7388 . catch ( ( /*error*/ ) => {
74- console . log ( { put_error : key } ) ;
89+ log ( { put_error : key } ) ;
7590 b1 . close ( ) ;
76- } ) ;
91+ } )
92+ ) ;
7793 }
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