moved to new index -- +50% performance boost, still not done.

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2022-10-24 03:29:11 +03:00
parent fc36053293
commit 40f10250f5
6 changed files with 36 additions and 186 deletions

View File

@ -16,39 +16,6 @@ var index = require('../index')
//---------------------------------------------------------------------
//
// cached(<name>, <update>[, ...<args>])
// cached(<name>, <get>, <update>[, ...<args>])
// -> <func>
//
// NOTE: in the first case (no <get>) the first <args> item can not be
// a function...
//
// XXX better introspection???
var cached =
module.cached =
function(name, get, update, ...args){
name = `__${name}_cache`
if(typeof(update) != 'function'){
args.unshift(update)
update = get
get = null }
return update instanceof types.AsyncFunction ?
async function(){
var cache = this[name] =
this[name]
?? await update.call(this)
return get ?
get.call(this, cache, ...arguments)
: cache }
: function(){
var cache = this[name] =
this[name]
?? update.call(this)
return get ?
get.call(this, cache, ...arguments)
: cache } }
//---------------------------------------------------------------------
@ -76,9 +43,9 @@ function(name, get, update, ...args){
// When overloading it is needed to to call the super method to
// retain base functionality.
// All overloading here is optional.
// .paths()
// .paths
// -> <path-list>
// .names()
// .names
// -> <name-index>
//
// .exists(<path>)
@ -160,23 +127,23 @@ module.BaseStore = {
return index.index(this, ...arguments) },
// XXX INDEX...
__xpaths__: async function(){
__paths__: async function(){
return Object.keys(this.data) },
// XXX unique???
__xpaths_merge__: async function(data){
__paths_merge__: async function(data){
return (await data)
.concat((this.next
&& 'xpaths' in this.next) ?
await this.next.xpaths
&& 'paths' in this.next) ?
await this.next.paths
: []) },
__xpaths_isvalid__: function(t){
__paths_isvalid__: function(t){
var changed =
!!this.__xpaths_next_exists != !!this.next
!!this.__paths_next_exists != !!this.next
|| (!!this.next
&& this.next.__xpaths_modified > t)
this.__xpaths_next_exists = !this.next
&& this.next.__paths_modified > t)
this.__paths_next_exists = !this.next
return changed },
__xpaths: index.makeIndex('xpaths', {
__paths: index.makeIndex('paths', {
update: async function(data, path){
data = await data
// XXX normalize???
@ -191,14 +158,14 @@ module.BaseStore = {
return data }, }),
// XXX should this clone the data???
// XXX should we use 'lazy'???
get xpaths(){
return this.__xpaths() },
get paths(){
return this.__paths() },
// NOTE: this is built from .paths so there is no need to define a
// way to merge...
__xnames: index.makeIndex('xnames',
__names: index.makeIndex('names',
function(){
return this.xpaths
return this.paths
.iter()
.reduce(function(res, path){
var n = pwpath.basename(path)
@ -226,76 +193,12 @@ module.BaseStore = {
return data }, }),
// XXX should this clone the data???
// XXX should we use 'lazy'???
get xnames(){
return this.__xnames() },
get names(){
return this.__names() },
// XXX tags
// XXX search
// XXX might be a good idea to cache this...
__paths__: async function(){
return Object.keys(this.data) },
// local paths...
__paths: cached('paths', async function(){
return this.__paths__() }),
// NOTE: this produces an unsorted list...
// XXX should this also be cached???
paths: async function(local=false){
return this.__paths()
.iter()
.concat((!local && (this.next || {}).paths) ?
this.next.paths()
: []) },
// XXX BUG: after caching this will ignore the local argument....
names: cached('names', async function(local=false){
return this.paths(local)
.iter()
.reduce(function(res, path){
var n = pwpath.basename(path)
if(!n.includes('*')){
(res[n] = res[n] ?? []).push(path) }
return res }, {}) }),
// XXX sort paths based on search order into three groups:
// - non-system
// ...sorted by length?
// - system
// ...sort based on system search order?
__sort_names: function(){},
__cache_add: function(path){
if(this.__paths_cache){
this.__paths_cache.includes(path)
|| this.__paths_cache.push(path) }
if(this.__names_cache){
var name = pwpath.basename(path)
var names = (this.__names_cache[name] =
this.__names_cache[name]
?? [])
names.includes(path)
|| names.push(path) }
return this },
__cache_remove: function(path){
if(this.__paths_cache){
var paths = this.__paths_cache
paths.splice(
paths.indexOf(
paths.includes(path) ?
path
: path[0] == '/' ?
path.slice(1)
: '/'+path),
1) }
if(this.__names_cache){
var name = pwpath.basename(path)
var names = (this.__names_cache[name] =
this.__names_cache[name]
?? [])
var i = names.indexOf(path)
i >= 0
&& names.splice(i, 1)
if(names.length == 0){
delete this.__names_cache[name] } }
return this },
//
// .exists(<path>)
@ -337,9 +240,7 @@ module.BaseStore = {
var {path, args} = pwpath.splitArgs(path)
args = pwpath.joinArgs('', args)
// build list of existing page candidates...
//var names = await this.names()
// XXX INDEX
var names = await this.xnames
var names = await this.names
var pages = new Set(
pwpath.names(path)
.map(function(name){
@ -408,7 +309,8 @@ module.BaseStore = {
await this.paths()
: await (this.names())[name])
/*/
return [...(await this.paths())
//return [...(await this.paths())
return [...(await this.paths)
//*/
// NOTE: we are not using .filter(..) here as wee
// need to keep parts of the path only and not
@ -593,8 +495,6 @@ module.BaseStore = {
data,
{mtime: Date.now()})
await this.__update__(path, data, mode)
// XXX CACHED
this.__cache_add(path)
// XXX INDEX
this.index('update', path)
this.onUpdate(path)
@ -609,8 +509,6 @@ module.BaseStore = {
path = await this.exists(path)
if(typeof(path) == 'string'){
await this.__delete__(path)
// XXX CACHED
this.__cache_remove(path)
// XXX INDEX
this.index('remove', path)
this.onDelete(path) }
@ -668,7 +566,8 @@ module.BaseStore = {
// generic...
} else {
var res = {}
for(var path of await this.paths()){
//for(var path of await this.paths()){
for(var path of await this.paths){
var page = await this.get(path)
if(keep_funcs
|| typeof(page) != 'function'){
@ -763,46 +662,32 @@ module.MetaStore = {
// their own stuff...
// XXX INDEX...
__xpaths_merge__: async function(data){
__paths_merge__: async function(data){
var that = this
var stores = await Promise.iter(
Object.entries(this.substores ?? {})
.map(function([path, store]){
return store.xpaths
return store.paths
.iter()
.map(function(s){
return pwpath.join(path, s) }) }))
.flat()
return object.parentCall(MetaStore.__xpaths_merge__, this, ...arguments)
return object.parentCall(MetaStore.__paths_merge__, this, ...arguments)
.iter()
.concat(stores) },
__xpaths_isvalid__: function(t){
__paths_isvalid__: function(t){
if(this.substores){
// match substore list...
var cur = Object.keys(this.substores ?? {})
var prev = this.__xpaths_substores ?? cur ?? []
var prev = this.__paths_substores ?? cur ?? []
if(prev.length != cur.length
|| (new Set([...cur, ...prev])).size != cur.length){
return false }
// check timestamps...
for(var {__xpaths_modified} of Object.values(this.substores ?? {})){
if(__xpaths_modified > t){
for(var {__paths_modified} of Object.values(this.substores ?? {})){
if(__paths_modified > t){
return false } } }
return object.parentCall(MetaStore.__xpaths_isvalid__, this, ...arguments) },
paths: async function(){
var that = this
var stores = await Promise.iter(
Object.entries(this.substores ?? {})
.map(function([path, store]){
return store.paths()
.iter()
.map(function(s){
return pwpath.join(path, s) }) }))
.flat()
return object.parentCall(MetaStore.paths, this, ...arguments)
.iter()
.concat(stores) },
return object.parentCall(MetaStore.__paths_isvalid__, this, ...arguments) },
exists: metaProxy('exists',
//async function(path){
@ -851,7 +736,7 @@ module.MetaStore = {
// trim path...
path.slice(path.indexOf(p)+p.length),
...[...arguments].slice(1))
this.__cache_add(path)
//this.__cache_add(path)
// XXX INDEX
this.index('update', path)
return this }

View File

@ -565,21 +565,6 @@ module.FileStoreRO = {
.replace(/\$PWIKI/, this.__pwiki_path__) },
// XXX INDEX...
__xpaths__: async function(){
var that = this
return new Promise(function(resolve, reject){
glob(pwpath.join(that.__path__, '**/*'))
.on('end', function(paths){
Promise.all(paths
.map(async function(path){
return await module.exists(path) ?
decode(path)
.slice(that.__path__.length)
: [] }))
.then(function(paths){
resolve(paths.flat()) }) }) }) },
// XXX do we remove the extension???
// XXX cache???
__paths__: async function(){
var that = this
return new Promise(function(resolve, reject){

View File

@ -34,9 +34,6 @@ module.IndexedDBStore = {
?? (this.__data = idb.createStore(this.__db__, this.__store__)) },
// XXX INDEX...
__xpaths__: function(){
return idb.keys(this.data) },
__paths__: function(){
return idb.keys(this.data) },
__exists__: function(path){

View File

@ -30,15 +30,6 @@ module.localStorageStore = {
: undefined,
// XXX INDEX...
__xpaths__: function(){
var that = this
return Object.keys(this.data)
.map(function(k){
return k.startsWith(that.__prefix__) ?
k.slice((that.__prefix__ ?? '').length)
: [] })
.flat() },
__paths__: function(){
var that = this
return Object.keys(this.data)

View File

@ -35,14 +35,6 @@ module.PouchDBStore = {
this.__data = value },
// XXX INDEX...
__xpaths__: async function(){
var that = this
// XXX not sure if this is a good idea...
return (await this.data.allDocs()).rows
.map(function(e){
return e.id.slice(that.__key_prefix__.length) }) },
// XXX cache???
__paths__: async function(){
var that = this
// XXX not sure if this is a good idea...

View File

@ -21,9 +21,9 @@
* ....i.e. in .update(..)/.delete(..) vs. .onUpdate(..)/.onDelete(..) ???
* XXX INDEX move to the new index...
* - .names - DONE
* - .paths -
* - events/methods -
* - cleanup -
* - .paths - DONE
* - handling - DONE
* - cleanup - DONE
* XXX INDEX DOC can index validation be async???
* ...likely no
* XXX INDEX add option to set default action (get/lazy/cached)