woops, fix unlinking nested

This commit is contained in:
Mark Nadal 2021-04-20 05:39:56 -07:00
parent 3b1509f40f
commit 0da0144828
2 changed files with 60 additions and 17 deletions

22
gun.js
View File

@ -722,7 +722,6 @@
function unlink(msg, cat){ // ugh, so much code for seemingly edge case behavior.
var put = msg.put||'', change = put['=']||put[':'], root = cat.root, link, tmp;
//if(!cat.has){ return } // MARK COME BACK HERE !!!!!!!!!!!!!!!! undef not need to trigger undef! No, already?
if(u === change){ // 1st edge case: If we have a brand new database, no data will be found.
// TODO: BUG! because emptying cache could be async from below, make sure we are not emptying a newer cache. So maybe pass an Async ID to check against?
// TODO: BUG! What if this is a map? // Warning! Clearing things out needs to be robust against sync/async ops, or else you'll see `map val get put` test catastrophically fail because map attempts to link when parent graph is streamed before child value gets set. Need to differentiate between lack acks and force clearing.
@ -730,28 +729,27 @@
//if(!cat.has){ return }
tmp = (msg.$$||msg.$||'')._||'';
if(msg['@'] && (u !== tmp.put || u !== cat.put)){ return } // a "not found" from other peers should not clear out data if we have already found it.
if(cat.has && u === cat.put && !(root.pass||'')[cat.id]){ return } // if we are already unlinked, do not call again, unless edge case.
//console.log('unlink:', cat.id, cat.has, msg, cat.link, '?', cat.put, change, '!!!', (root.pass||'')[cat.id]);
//if(cat.has && u === cat.put && !(root.pass||'')[cat.id]){ return } // if we are already unlinked, do not call again, unless edge case. // TODO: BUG! This line should be deleted for "unlink deeply nested".
if(link = cat.link){
delete (root.$.get(link)._.echo||'')[cat.id];
}
if(cat.has){ // TODO: Empty out links, maps, echos, acks/asks, etc.?
if(tmp = cat.link){
delete (root.$.get(tmp)._.echo||'')[cat.id];
}
cat.link = null;
}
cat.put = u; // empty out the cache if, for example, alice's car's color no longer exists (relative to alice) if alice no longer has a car.
// TODO: BUG! For maps, proxy this so the individual sub is triggered, not all subs.
//console.log("unlink!", cat.id, msg, cat);
setTimeout.each(Object.keys(cat.next||''), function(get, sat){ // empty out all sub chains. // TODO: .keys( is slow // BUG? ?Some re-in logic may depend on this being sync? // TODO: BUG? This will trigger deeper put first, does put logic depend on nested order? // TODO: BUG! For map, this needs to be the isolated child, not all of them.
if(!(sat = cat.next[get])){ return }
if(cat.has && u === sat.put && !(root.pass||'')[sat.id]){ return } // if we are already unlinked, do not call again, unless edge case.
//if(cat.has && u === sat.put && !(root.pass||'')[sat.id]){ return } // if we are already unlinked, do not call again, unless edge case. // TODO: BUG! This line should be deleted for "unlink deeply nested".
if(link){ delete (root.$.get(link).get(get)._.echo||'')[sat.id] }
sat.on('in', {get: get, put: u, $: sat.$}); // TODO: BUG? Add recursive seen check?
},0,99);
return;
}
if(cat.soul){ return } // a soul cannot unlink itself.
if(msg.$$){ return } // a linked chain does not do the unlinking, the sub chain does. // TODO: BUG? Will this cancel maps?
link = valid(change); // need to unlink anytime we are not the same link, though only do this once per unlink.
tmp = msg.$._;
link = valid(change); // need to unlink anytime we are not the same link, though only do this once per unlink (and not on init).
tmp = msg.$._||'';
if(link === tmp.link || (cat.has && !tmp.link)){
if((root.pass||'')[cat.id] && 'string' !== typeof link){
@ -759,8 +757,8 @@
return;
}
}
unlink({get: cat.get, put: u, $: cat.$}, cat); // unlink our sub chains.
delete (msg.$._.echo||'')[cat.id];
delete (tmp.echo||'')[cat.id];
unlink({get: cat.get, put: u, $: msg.$}, cat); // unlink our sub chains.
}; Gun.on.unlink = unlink;
function ack(msg, ev){

View File

@ -1511,7 +1511,7 @@ describe('Gun', function(){
}, 1000);
});
it('uncached synchronous map on get node mutate node uncached', function(done){
it.only('uncached synchronous map on get node mutate node uncached', function(done){
Gun.statedisk({
alice: {_:{'#':'umaliceo3'},
age: 26,
@ -1528,15 +1528,15 @@ describe('Gun', function(){
gun.get('u/m/p/n/mutate/n/u').map().get('pet').on(function(v,f){
check[v.name] = f;
count[v.name] = (count[v.name] || 0) + 1;
//console.log("*****************", f,v);
console.log("*****************", f,v, check);
if(check.Fluffy && check.Frisky && check.Fuzzball){
clearTimeout(done.to);
done.to = setTimeout(function(){
expect(done.last).to.be.ok();
expect(check['Fluffs']).to.not.be.ok();
//expect(count.Fluffy).to.be(1);
//expect(count.Frisky).to.be(1);
//expect(count.Fuzzball).to.be(1);
expect(count.Fluffy).to.be(1);
expect(count.Frisky).to.be(1);
expect(count.Fuzzball).to.be(1);
done();
},200);
}
@ -1560,6 +1560,51 @@ describe('Gun', function(){
}, 1000);
});
it("unlink deeply nested", function(done){
Gun.statedisk({
a: {_:{'#':'audn'},
age: 26,
name: "Alice",
b: {_:{'#':'budn'}, c: {_:{'#':'cudn'}, id: 'first', level: 3}, level: 2}
}
}, 'udn', function() {
var check = {}, count = {};
gun.get('udn').get('a').get('b').get('c').on(function(data){
//console.log("udn.a.b.c:", data);
check[data.id] = 1;
count[data.id] = (count[data.id] || 0) + 1;
expect(data.foo).to.not.be.ok();
//console.log("*****************", f,v, check);
if(check.first && check.other){
clearTimeout(done.to);
done.to = setTimeout(function(){
expect(done.last).to.be.ok();
expect(check.firsta).to.not.be.ok();
expect(count.first).to.be(1);
expect(count.other).to.be(1);
done();
},200);
}
});
setTimeout(function(){
Gun.statedisk({
name: 'Alice2', age: 34,
b: {_:{'#':'2budn'}, c: {_:{'#':'2cudn'}, id: 'other', level: 3}, level: 2}
}, '2audn', function() {
//console.only.i=1;console.log('=============================');
gun.get('udn').put({
a: {'#':'2audn'}
});
setTimeout(function(){
//console.log("- - - - - - - - - - - -");
gun.get('cudn').put({id: 'firsta', foo: 'bar'});
done.last = 1;
}, 50);
});
},50);
});
});
it("get before put in memory", function(done){
var gun = Gun();
var check = {};