Re-scan code working faster

Signed-off-by: James Ketrenos <james_git@ketrenos.com>
This commit is contained in:
James Ketr 2018-09-24 11:16:20 -07:00
parent f3af3a5131
commit ef74300974
2 changed files with 74 additions and 9 deletions

2
server/db/photos.js Normal file → Executable file
View File

@ -53,10 +53,10 @@ function init() {
autoIncrement: true autoIncrement: true
}, },
name: Sequelize.STRING, name: Sequelize.STRING,
path: Sequelize.STRING,
filename: Sequelize.STRING, filename: Sequelize.STRING,
added: Sequelize.DATE, added: Sequelize.DATE,
modified: Sequelize.DATE, modified: Sequelize.DATE,
scanned: Sequelize.DATE,
taken: Sequelize.DATE, taken: Sequelize.DATE,
width: Sequelize.INTEGER, width: Sequelize.INTEGER,
height: Sequelize.INTEGER, height: Sequelize.INTEGER,

View File

@ -525,7 +525,9 @@ function scanDir(parent, path) {
assets.push({ assets.push({
path: path.slice(picturesPath.length), path: path.slice(picturesPath.length),
filename: file.replace(rawExtension, ".jpg"), /* We will be converting from NEF/ORF => JPG */ filename: file.replace(rawExtension, ".jpg"), /* We will be converting from NEF/ORF => JPG */
stats: stats name: file.replace(/.[^.]*$/, ""),
stats: stats,
parent: album
}); });
}); });
}); });
@ -538,6 +540,7 @@ function findOrCreateDBAlbum(album) {
let query = "SELECT id FROM albums WHERE path=:path AND "; let query = "SELECT id FROM albums WHERE path=:path AND ";
if (!album.parent) { if (!album.parent) {
query += "parentId IS NULL"; query += "parentId IS NULL";
album.parentId = null;
} else { } else {
if (!album.parent.id) { if (!album.parent.id) {
let error = "Albums in array in non ancestral order!"; let error = "Albums in array in non ancestral order!";
@ -553,8 +556,11 @@ function findOrCreateDBAlbum(album) {
type: photoDB.sequelize.QueryTypes.SELECT type: photoDB.sequelize.QueryTypes.SELECT
}).then(function(results) { }).then(function(results) {
if (results.length == 0) { if (results.length == 0) {
return photoDB.sequelize.query("INSERT INTO albums (path,parentId,name) VALUES(:path,:parent,:name)", { if (!album.parent) {
replacements: replacements console.warn("Creating top level album: " + album.path);
}
return photoDB.sequelize.query("INSERT INTO albums (path,parentId,name) VALUES(:path,:parentId,:name)", {
replacements: album
}).then(function(results) { }).then(function(results) {
return results[1].lastID; return results[1].lastID;
}); });
@ -562,7 +568,39 @@ function findOrCreateDBAlbum(album) {
return results[0].id; return results[0].id;
} }
}).then(function(id) { }).then(function(id) {
album.parentId = id; album.id = id;
return id;
});
}
function findOrUpdateDBAsset(asset) {
let query = "SELECT id FROM photos WHERE albumId=:albumId AND filename=:filename";
if (!asset.parent || !asset.parent.id) {
let error = "Asset being processed without a parent";
console.error(error);
throw error;
}
asset.albumId = asset.parent.id;
return photoDB.sequelize.query(query, {
replacements: asset,
type: photoDB.sequelize.QueryTypes.SELECT
}).then(function(results) {
if (results.length == 0) {
/* Not in DB at all; HASH needs to be created. We could use the sharp loader to create
* a buffer, then pass that around. It would complicate our code, so instead we will
* leverage the OS' ability to cache read-only file assets in the cache and to pass
* those to the sharp layer later :) Accordingly, we will load the file here, create a SHA
* and create that HASH entry (unless it already exists, in which case DUPLICATE!!!! Gah.) */
return photoDB.sequelize.query("INSERT INTO photos (albumId,filename,name) VALUES(:albumId,:filename,:name)", {
replacements: asset
}).then(function(results) {
return results[1].lastID;
});
} else {
return results[0].id;
}
}).then(function(id) {
asset.id = id;
return id; return id;
}); });
} }
@ -572,6 +610,8 @@ module.exports = {
photoDB = db; photoDB = db;
/* 1. Scan for all assets which will be managed by the system. readdir /* 1. Scan for all assets which will be managed by the system. readdir
* 2. Check if entry in DB. Check mod-time in DB vs. stats from #1 * 2. Check if entry in DB. Check mod-time in DB vs. stats from #1
* - For albums
* - For assets
* 3. If not in DB, or mod-time changed, compute HASH of the file * 3. If not in DB, or mod-time changed, compute HASH of the file
* 4. Check for HASH in photohash -- skip? * 4. Check for HASH in photohash -- skip?
* 5. Check for and create thumbs/FILE thumbs/scaled/FILE * 5. Check for and create thumbs/FILE thumbs/scaled/FILE
@ -584,10 +624,35 @@ module.exports = {
return scanDir(null, picturesPath).spread(function(albums, assets) { return scanDir(null, picturesPath).spread(function(albums, assets) {
console.log("Found " + assets.length + " assets in " + albums.length + " albums after " + console.log("Found " + assets.length + " assets in " + albums.length + " albums after " +
((Date.now() - now) / 1000) + "s"); ((Date.now() - now) / 1000) + "s");
return Promise.map(albums, function(album) { /* One at a time, in series, as the album[] array has parents first, then descendants.
return db.sequelize * Operating in parallel could result in a child being searched for prior to the parent */
}, { now = Date.now();
concurrency: 5
return Promise.mapSeries(albums, function(album) {
return findOrCreateDBAlbum(album);
}).then(function() {
console.log("Processed " + albums.length + " album DB entries in " +
((Date.now() - now) / 1000) + "s");
now = Date.now();
let processed = 0, start = Date.now(), last = 0;
return Promise.map(assets, function(asset) {
return findOrUpdateDBAsset(asset).then(function() {
let elapsed = Date.now() - start;
processed++;
if (elapsed > 5000) {
let remaining = assets.length - processed;
console.log(remaining + " assets remaining. ETA " + Math.ceil((elapsed / 1000) * remaining / (processed - last)) + "s");
last = processed;
start = Date.now();
}
});
}, {
concurrency: 5
}).then(function() {
console.log("Processed " + assets.length + " asset DB entries in " +
((Date.now() - now) / 1000) + "s");
});
}); });
/*triggerWatcher();*/ /*triggerWatcher();*/
}); });