thanks @rogowski book test read/memory/disk variations

This commit is contained in:
Mark Nadal 2023-01-30 15:29:30 -08:00
parent 9abebd7673
commit 0665787e2b
3 changed files with 122 additions and 19 deletions

View File

@ -28,6 +28,7 @@ var sT = setTimeout, B = sT.Book || (sT.Book = function(text){
function page(word){
var b = this, l = b.list, i = spot(B.encode(word), l), p = l[i];
if('string' == typeof p){ l[i] = p = {size: -1, first: p, substring: sub, toString: to, book: b, get: b} } // TODO: test, how do we arrive at this condition again?
p.i = i;
return p;
// TODO: BUG! What if we get the page, it turns out to be too big & split, we must then RE get the page!
}
@ -81,7 +82,7 @@ function set(word, is){
page.sort = 1;
b(word, is);
page.size += size(word) + size(is);
if(PAGE < page.size){ split(page, b) }
if((b.PAGE || PAGE) < page.size){ split(page, b) }
return b;
}
@ -112,16 +113,16 @@ function size(t){ return (t||'').length||1 } // bits/numbers less size? Bug or f
function subt(i,j){ return this.word }
//function tot(){ return this.text = this.text || "'"+(this.word)+"'"+(this.is)+"'" }
function tot(){ var tmp;
if((tmp = this.page) && tmp.saving){ delete tmp.book.all[this.word]; }
//if((tmp = this.page) && tmp.saving){ delete tmp.book.all[this.word]; } // TODO: BUG! Book can't know about RAD, this was from RAD, so this MIGHT be correct but we need to refactor. Make sure to add tests that will re-trigger this.
return this.text = this.text || "'"+(this.word)+"'"+(this.is)+"'";
}
function sub(i,j){ return (this.first||this.word||(from(this)||'')[0]||'').substring(i,j) }
function to(){ return this.text = this.text || text(this) }
function join(){ return this.join('|') }
function text(p){
if(!p.list){ return (p.from||'')+'' }
if(!p.from){ return '|'+((p.list && (p.list = p.list.sort()).join('|'))||'')+'|' }
return '|'+/*from(p).concat(p.list)*/p.list.sort().join('|')+'|'; // commenting out this sub-portion of code fixed a more basic test, but will probably cause a bug with a FROM + MEMORY.
if(!p.list){ return (typeof p.from == 'string')? (p.from||'')+'' : '|'+p.from+'|' }
if(!p.from){ return '|'+((p.list && (p.list = p.list.sort()).join('|'))||'')+'|' }
return '|'+from(p).concat(p.list).sort().join('|')+'|'; // commenting out this sub-portion of code fixed a more basic test, but will probably cause a bug with a FROM + MEMORY.
}
B.encode = function(d, _){ _ = _ || "'";
@ -144,4 +145,4 @@ B.hash = function(s, c){ // via SO
}
try{module.exports=B}catch(e){}
}());
}());

View File

@ -20,6 +20,7 @@
//console.log("OFF");return;
// ON WRITE:
// batch until read from disk is done (and if a write was going, do that first)
if(!valid(word, is, reply)){ return }
b(word, is);
write(word, reply);
return r;
@ -27,12 +28,34 @@
async function read(word, reply, page){
var p = page;//b.page(word);
var p = page || b.page(word);
reply = reply.call ? reply : () => { };
log(`read() ${word.slice(0, 40)}`);
get(p, function(err, disk){
if(err){ log("ERR! in read() get() cb", err); reply(err); return }
p.from = disk || p.from;
if(!disk){
// do something to show whatever we have in-memory is going to be the disk.
}
if(disk){
disk = Book(p.from = disk);
disk.PAGE = Infinity; // THIS BOOK IS ONLY TEMPORARY!
(p.list||[]).forEach(function(has){
disk(has.word, has.is);
});
// TODO: BUG! What happens if the merge causes too large of a page and it splits... WRITE TESTS TO HANDLE.
disk = disk.list[0];
disk.first = p.first = (disk.first < p.first? disk.first : p.first);
/*disk.book = disk.get = b;
disk.saving = p.saving;
disk.i = p.i;
p = b.list[p.i] = disk;*/
p.from = disk.from;
p.list = disk.list;
p.size = disk.size;
p.text = disk.text;
} else {
//p.from = disk || p.from; // TODO: NEED TO MERGE! AND HANDLE ERR!
}
//p.from = disk || p.from;
reply(null, p, b);
})
}
@ -42,13 +65,13 @@
var p = b.page(word), tmp;
if(tmp = p.saving){ reply && tmp.push(reply); return } p.saving = [reply];
var S = +new Date; log(" writing", p.substring(), 'since last', S - p.saved, RAD.c, 'records', env.count++, 'mid-swap.');
get(p, function(err, disk){
read(p, function(err, disk){
if(err){ log("ERR! in write() get() cb ", err); return }
//log(' get() - p.saving ', (p.saving || []).length);
if(p.from && disk){
//log(" get() merge: p.from ", p.toString().slice(0, 40), " disk.length", disk?.length || 0);
}
p.from = disk || p.from; // TODO: NEED TO MERGE! AND HANDLE ERR!
// CODE CUT OUT AND MOVED TO READ
// var save = '' + p; if(!p.from){ p.from = save }
// p.list = p.text = p.from = 0;
// p.first = p.first.word || p.first;
@ -59,7 +82,7 @@
// log({ tmp });
write(word, reply);
});
})
}, p);
}
function put(file, data, cb){
file.first && (file = Book.slot(file.first)[0]);
@ -117,6 +140,11 @@
function ename(t) { return encodeURIComponent(t).replace(/\*/g, '%2A').slice(0, 250) }
function fname(p) { return opt.file + '/' + ename(p.substring()) }
function valid(word, is, reply){
if(is !== is){ reply(word +" cannot be NaN!"); return }
return true;
}
return r;
}), MAX = 1000/* 300000000 */;

View File

@ -32,10 +32,10 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
var opt = {};
opt.file = 'radatatest';
var Radisk = (setTimeout.RAD) || require('../../lib/radisk');
var RAD = (setTimeout.RAD) || require('../../lib/radisk');
//opt.store = ((Gun.window && Gun.window.RindexedDB) || require('../../lib/rfs'))(opt);
opt.chunk = 1000;
var rad = Radisk(opt), esc = String.fromCharCode(27);
var rad = RAD(opt), esc = String.fromCharCode(27);
describe('Book', function(){
this.timeout(1000 * 9);
@ -89,10 +89,10 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
false,
-Infinity,
Infinity,
NaN,
-0
];
var prim = ['alice', 'bob'];
//var prim = ['alice', 'bob'];
//var prim = [null];
root.rad = rad;
describe('can in-memory write & read all primitives', done => { prim.forEach(function(type){
@ -106,11 +106,10 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
});});
describe('can disk write & read all primitives', done => { prim.forEach(function(type){
var r = rad;
it('save '+type, done => { setTimeout(function(){
r('type-'+type, type, function(err, ok){
rad('type-'+type, type, function(err, ok){
expect(err).to.not.be.ok();
r('type-'+type, function(err, page){
rad('type-'+type, function(err, page){
var val = page.get('type-'+type);
expect(val).to.be(type);
done();
@ -119,6 +118,81 @@ var names = ["Adalard","Adora","Aia","Albertina","Alfie","Allyn","Amabil","Ammam
},1); });
});});
describe('error on invalid primitives', function(){
it('test invalid', done => {
rad('type-NaN', NaN, function(err, ok){
expect(err).to.be.ok();
done();
});
});
});
describe('Async Race Conditions', function(){
it('make sure word does not get duplicated when data is re-saved after read', done => {
var opt = {file: 'zadata'}
var prev = RAD(opt);
prev('helloz', 'world', function(err, ok){
prev('helloz', function(err, page){
prev('zalice', 'yay', function(err){
expect(page.text.split('helloz').length).to.be(2);
done();
});
});
});
/*
(A) READ ONLY: we receive a message, we READ only - parseless is important.
(B) READ & WRITE: we write a page, and it already exists on disk.
(C) WRITE ONLY: we write a page, and it is new to disk.
*/
});
it('test if adding an in-memory word merges with previously written disk data', done => {
var prev = RAD(opt);
prev('pa-alice', 'hello', function(err, ok){
expect(err).to.not.be.ok();
setTimeout(function(){
var rad = RAD(opt);
rad('pa-bob', 'banana', function(err, ok){
expect(err).to.not.be.ok();
//console.log("COMPARE:", rad.book.list[0].text, 'vs', prev.book.list[0].text);
var text = rad.book.list[0].text;
var i = text.indexOf('pa-alice');
expect(i).to.not.be(-1);
var ii = text.indexOf('hello');
expect((ii - i) < 10).to.be.ok();
done();
})
},99);
});
});
it('test if updating an in-memory word merges with previously written disk data', done => {
var prev = RAD(opt);
prev('pu-alice', 'hello', function(err, ok){
expect(err).to.not.be.ok();
var rad = RAD(opt);
rad('pu-alice', 'cool', function(err, ok){
expect(err).to.not.be.ok();
var next = RAD(opt);
next('pu-alice', function(err, page){
expect('cool').to.be(page.get('pu-alice'));
done();
})
});
});
});
});
});
var ntmp = names;