diff --git a/gun.js b/gun.js index 0fe78cf8..04e072f8 100644 --- a/gun.js +++ b/gun.js @@ -1994,8 +1994,8 @@ try{msg = msg || JSON.parse(raw); }catch(e){return opt.log('DAM JSON parse error', e)} if(!msg){ return } - if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear') } if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } + if(msg.DBG_s){ console.log(+new Date - msg.DBG_s, 'to hear', id) } if(dup.check(id)){ return } dup.track(id, true).it = msg; // GUN core also dedups, so `true` is needed. // Does GUN core need to dedup anymore? if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } @@ -2027,7 +2027,7 @@ if(this.to){ this.to.next(msg) } // compatible with middleware adapters. if(!msg){ return false } var id, hash, tmp, raw; - var S = +new Date; + var S = +new Date; // msg.DBG_s = msg.DBG_s || +new Date; var meta = msg._||(msg._=function(){}); if(!(id = msg['#'])){ id = msg['#'] = Type.text.random(9) } if(!(hash = msg['##']) && u !== msg.put){ hash = msg['##'] = Type.obj.hash(msg.put) } @@ -2262,6 +2262,7 @@ wire.onerror = function(error){ reconnect(peer); }; + // it can take a while to open a socket, maybe no longer lazy load for perf reasons? wire.onopen = function(){ opt.mesh.hi(peer); } diff --git a/lib/radisk.js b/lib/radisk.js index 9eba437f..e918e6ce 100644 --- a/lib/radisk.js +++ b/lib/radisk.js @@ -244,7 +244,7 @@ // if a node is requested and some of it is cached... the other parts might not be. //} } - o.span = (u !== o.start) || (u !== o.end); + o.span = (u !== o.start) || (u !== o.end); // is there a start or end? var g = function Get(){}; g.lex = function(file){ var tmp; file = (u === file)? u : decodeURIComponent(file); @@ -277,19 +277,24 @@ } g.ack = function(as){ if(!as.ack){ return } - var tmp = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(tmp), o), last = rad.last || Radix.map(rad, rev, revo); + var key = as.key, o = as.opt, info = g.info, rad = g.disk || noop, data = r.range(rad(key), o), last = rad.last || Radix.map(rad, rev, revo); o.parsed = (o.parsed || 0) + (info.parsed||0); o.chunks = (o.chunks || 0) + 1; - if(!o.some){ o.some = (u !== data) } - if(u !== data){ as.ack(g.err, data, o) } - else if(!as.file){ !o.some && as.ack(g.err, u, o); return } - if(!o.span){ - if(/*!last || */last === tmp){ !o.some && as.ack(g.err, u, o); return } - if(last && last > tmp && 0 != last.indexOf(tmp)){ !o.some && as.ack(g.err, u, o); return } + o.more = true; + if((!as.file) // if no more places to look + || (!o.span && last === key) // if our key exactly matches the very last atomic record + || (!o.span && last && last > key && 0 != last.indexOf(key)) // 'zach' may be lexically larger than 'za', but there still might be more, like 'zane' in the 'za' prefix bucket so do not end here. + ){ + o.more = u; + as.ack(g.err, data, o); + return } - if(o.some && o.parsed >= o.limit){ return } + if(u !== data){ + as.ack(g.err, data, o); // more might be coming! + if(o.parsed >= o.limit){ return } // even if more, we've hit our limit, asking peer will need to make a new ask with a new starting point. + } o.next = as.file; - r.read(tmp, as.ack, o); + r.read(key, as.ack, o); } if(o.reverse){ g.lex.reverse = true } LOG && (S = +new Date); @@ -313,7 +318,7 @@ var p = function Parse(){}, info = {}; p.disk = Radix(); p.read = function(err, data){ var tmp; - LOG && console.log('read disk in', +new Date - start, ename(file)); // keep this commented out in + LOG && console.log('read disk in', +new Date - S, ename(file)); // keep this commented out in delete Q[file]; if((p.err = err) || (p.not = !data)){ return map(q, p.ack); @@ -330,12 +335,12 @@ } info.parsed = data.length; - LOG && (start = +new Date); // keep this commented out in production! - if(opt.jsonify){ // temporary testing idea + LOG && (S = +new Date); // keep this commented out in production! + if(opt.jsonify || '{' === data[0]){ // temporary testing idea try{ var json = JSON.parse(data); p.disk.$ = json; - LOG && console.log('parsed JSON in', +new Date - start); // keep this commented out in production! + LOG && console.log('parsed JSON in', +new Date - S); // keep this commented out in production! map(q, p.ack); return; }catch(e){ tmp = e } @@ -344,7 +349,7 @@ return map(q, p.ack); } } - LOG && (start = +new Date); // keep this commented out in production! + LOG && (S = +new Date); // keep this commented out in production! var tmp = p.split(data), pre = [], i, k, v; if(!tmp || 0 !== tmp[1]){ p.err = "File '"+file+"' does not have root radix! "; @@ -367,7 +372,7 @@ if(u !== k && u !== v){ p.disk(pre.join(''), v) } tmp = p.split(tmp[2]); } - LOG && console.log('parsed RAD in', +new Date - start); // keep this commented out in production! + LOG && console.log('parsed RAD in', +new Date - S); // keep this commented out in production! //cb(err, p.disk); map(q, p.ack); }; @@ -387,7 +392,7 @@ if(p.err || p.not){ return cb(p.err, u, info) } cb(u, p.disk, info); } - var start; LOG && (start = +new Date); // keep this commented out in production! + var S; LOG && (S = +new Date); // keep this commented out in production! if(raw){ return p.read(null, raw) } opt.store.get(ename(file), p.read); } diff --git a/lib/store.js b/lib/store.js index 0d0cdaf2..49559ea0 100644 --- a/lib/store.js +++ b/lib/store.js @@ -3,7 +3,7 @@ var Gun = (typeof window !== "undefined")? window.Gun : require('../gun'); Gun.on('create', function(root){ if(Gun.TESTING){ root.opt.file = 'radatatest' } this.to.next(root); - var opt = root.opt, u; + var opt = root.opt, empty = {}, u; if(false === opt.radisk){ return } var Radisk = (Gun.window && Gun.window.Radisk) || require('./radisk'); var Radix = Radisk.Radix; @@ -14,9 +14,17 @@ Gun.on('create', function(root){ root.on('put', function(msg){ this.to.next(msg); var id = msg['#'] || Gun.text.random(3), track = !msg['@'], acks = track? 0 : u; // only ack non-acks. - if(msg.rad && !track){ return } // don't save our own acks + var got = (msg._||empty).rad, now = Gun.state(); var S = (+new Date); // STATS! Gun.graph.is(msg.put, null, function(val, key, node, soul){ + if(!track && got){ + var at = (root.next||empty)[soul]; + if(!at){ return } + if(u !== got['.']){ at = (at.next||empty)[key] } + if(!at){ return } + at.rad = now; + return; + } if(track){ ++acks } //console.log('put:', soul, key, val); val = Radisk.encode(val, null, esc)+'>'+Radisk.encode(Gun.state.is(node, key), null, esc); @@ -69,17 +77,24 @@ Gun.on('create', function(root){ o.limit = (tmp <= (o.pack || (1000 * 100)))? tmp : 1; } if(has['-'] || (soul||{})['-']){ o.reverse = true } + if(tmp = (root.next||empty)[soul]){ + if(tmp && tmp.rad){ return } + if(o.atom){ tmp = (tmp.next||empty)[o.atom] } + if(tmp && tmp.rad){ return } + } var S = (+new Date); // STATS! // console.log("GET!", id, JSON.stringify(key)); rad(key||'', function(err, data, o){ try{opt.store.stats.get.time[statg % 50] = (+new Date) - S; ++statg; opt.store.stats.get.count++; if(err){ opt.store.stats.get.err = err } }catch(e){} // STATS! + //if(u === data && o.chunks > 1){ return } // if we already sent a chunk, ignore ending empty responses. // this causes tests to fail. console.log(+new Date - S, 'got'); S = +new Date; if(data){ if(typeof data !== 'string'){ if(o.atom){ data = u; + Radix.map(data, each) } else { Radix.map(data, each) } @@ -87,7 +102,7 @@ Gun.on('create', function(root){ if(!graph && data){ each(data, '') } } console.log(+new Date - S, 'got prep'); S = +new Date; - root.on('in', {'@': id, put: graph, err: err? err : u, rad: Radix}); + root.on('in', {'@': id, put: graph, '%': o.more? 1 : u, err: err? err : u, _: each}); console.log(+new Date - S, 'got sent'); }, o); console.log(+new Date - S, 'get call'); @@ -97,12 +112,13 @@ Gun.on('create', function(root){ var soul = has.slice(0,1)[0]; has = has.slice(-1)[0]; o.count = (o.count || 0) + val.length; - tmp = val.lastIndexOf('>'); + var tmp = val.lastIndexOf('>'); var state = Radisk.decode(val.slice(tmp+1), null, esc); val = Radisk.decode(val.slice(0,tmp), null, esc); (graph = graph || {})[soul] = Gun.state.ify(graph[soul], has, state, val, soul); if(o.limit && o.limit <= o.count){ return true } } + each.rad = get; }); opt.store.stats = {get:{time:{}, count:0}, put: {time:{}, count:0}}; // STATS! var statg = 0, statp = 0; // STATS! diff --git a/test/rad/rad.js b/test/rad/rad.js index 6d07686e..d1a638d2 100644 --- a/test/rad/rad.js +++ b/test/rad/rad.js @@ -190,12 +190,13 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam if(opt.end < v){ return } if(v.indexOf(find) == 0){ all[v] = true } }); - rad(find, function(err, data){ + rad(find, function(err, data, o){ Radix.map(data, function(v,k){ //console.log(find+k, v); delete all[find+k]; }); if(!Gun.obj.empty(all)){ return } + if(!data){ return } // in case there is "more" that returned empty done(); }, opt); });