disable automatic blob expiration since we can't quite rely on atime as an inactivity metric
This commit is contained in:
parent
f2db93834b
commit
8326b8b270
@ -41,6 +41,7 @@
|
|||||||
"flow": "./node_modules/.bin/flow",
|
"flow": "./node_modules/.bin/flow",
|
||||||
"test": "node scripts/TestSelenium.js",
|
"test": "node scripts/TestSelenium.js",
|
||||||
"test-rpc": "cd scripts/tests && node test-rpc",
|
"test-rpc": "cd scripts/tests && node test-rpc",
|
||||||
"template": "cd customize.dist/src && for page in ../index.html ../privacy.html ../terms.html ../about.html ../contact.html ../what-is-cryptpad.html ../features.html ../../www/login/index.html ../../www/register/index.html ../../www/user/index.html;do echo $page; cp template.html $page; done;"
|
"template": "cd customize.dist/src && for page in ../index.html ../privacy.html ../terms.html ../about.html ../contact.html ../what-is-cryptpad.html ../features.html ../../www/login/index.html ../../www/register/index.html ../../www/user/index.html;do echo $page; cp template.html $page; done;",
|
||||||
|
"evict-inactive": "node scripts/evict-inactive.js"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
var nThen = require("nthen");
|
var nThen = require("nthen");
|
||||||
|
|
||||||
var Store = require("../storage/file");
|
var Store = require("../storage/file");
|
||||||
|
var BlobStore = require("../storage/blob");
|
||||||
var Pinned = require("./pinned");
|
var Pinned = require("./pinned");
|
||||||
var config = require("../lib/load-config");
|
var config = require("../lib/load-config");
|
||||||
|
|
||||||
@ -14,9 +15,16 @@ var inactiveTime = +new Date() - (config.inactiveTime * 24 * 3600 * 1000);
|
|||||||
// files which were archived before this date can be considered safe to remove
|
// files which were archived before this date can be considered safe to remove
|
||||||
var retentionTime = +new Date() - (config.archiveRetentionTime * 24 * 3600 * 1000);
|
var retentionTime = +new Date() - (config.archiveRetentionTime * 24 * 3600 * 1000);
|
||||||
|
|
||||||
|
var getNewestTime = function (stats) {
|
||||||
|
return stats[['atime', 'ctime', 'mtime'].reduce(function (a, b) {
|
||||||
|
return stats[b] > stats[a]? b: a;
|
||||||
|
})];
|
||||||
|
};
|
||||||
|
|
||||||
var store;
|
var store;
|
||||||
var pins;
|
var pins;
|
||||||
var Log;
|
var Log;
|
||||||
|
var blobs;
|
||||||
nThen(function (w) {
|
nThen(function (w) {
|
||||||
// load the store which will be used for iterating over channels
|
// load the store which will be used for iterating over channels
|
||||||
// and performing operations like archival and deletion
|
// and performing operations like archival and deletion
|
||||||
@ -40,8 +48,17 @@ nThen(function (w) {
|
|||||||
Logger.create(config, w(function (_) {
|
Logger.create(config, w(function (_) {
|
||||||
Log = _;
|
Log = _;
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
config.getSession = function () {};
|
||||||
|
BlobStore.create(config, w(function (err, _) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
return console.error(err);
|
||||||
|
}
|
||||||
|
blobs = _;
|
||||||
|
}));
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
// this block will iterate over archived channels and remove them
|
// this block will iterate over archived channels and removes them
|
||||||
// if they've been in cold storage for longer than your configured archive time
|
// if they've been in cold storage for longer than your configured archive time
|
||||||
|
|
||||||
// if the admin has not set an 'archiveRetentionTime', this block makes no sense
|
// if the admin has not set an 'archiveRetentionTime', this block makes no sense
|
||||||
@ -89,6 +106,104 @@ nThen(function (w) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
store.listArchivedChannels(handler, w(done));
|
store.listArchivedChannels(handler, w(done));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
if (typeof(config.archiveRetentionTime) !== "number") { return; }
|
||||||
|
var removed = 0;
|
||||||
|
blobs.list.archived.proofs(function (err, item, next) {
|
||||||
|
if (err) {
|
||||||
|
Log.error("EVICT_BLOB_LIST_ARCHIVED_PROOF_ERROR", err);
|
||||||
|
return void next();
|
||||||
|
}
|
||||||
|
if (pins[item.blobId]) { return void next(); }
|
||||||
|
if (item && getNewestTime(item) > retentionTime) { return void next(); }
|
||||||
|
blobs.remove.archived.proof(item.safeKey, item.blobId, (function (err) {
|
||||||
|
if (err) {
|
||||||
|
Log.error("EVICT_ARCHIVED_BLOB_PROOF_ERROR", item);
|
||||||
|
return void next();
|
||||||
|
}
|
||||||
|
Log.info("EVICT_ARCHIVED_BLOB_PROOF", item);
|
||||||
|
removed++;
|
||||||
|
next();
|
||||||
|
}));
|
||||||
|
}, w(function () {
|
||||||
|
Log.info('EVICT_ARCHIVED_BLOB_PROOFS_REMOVED', removed);
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
if (typeof(config.archiveRetentionTime) !== "number") { return; }
|
||||||
|
var removed = 0;
|
||||||
|
blobs.list.archived.blobs(function (err, item, next) {
|
||||||
|
if (err) {
|
||||||
|
Log.error("EVICT_BLOB_LIST_ARCHIVED_BLOBS_ERROR", err);
|
||||||
|
return void next();
|
||||||
|
}
|
||||||
|
if (pins[item.blobId]) { return void next(); }
|
||||||
|
if (item && getNewestTime(item) > retentionTime) { return void next(); }
|
||||||
|
blobs.remove.archived.blob(item.blobId, function (err) {
|
||||||
|
if (err) {
|
||||||
|
Log.error("EVICT_ARCHIVED_BLOB_ERROR", item);
|
||||||
|
return void next();
|
||||||
|
}
|
||||||
|
Log.info("EVICT_ARCHIVED_BLOB", item);
|
||||||
|
removed++;
|
||||||
|
next();
|
||||||
|
});
|
||||||
|
}, w(function () {
|
||||||
|
Log.info('EVICT_ARCHIVED_BLOBS_REMOVED', removed);
|
||||||
|
}));
|
||||||
|
/* TODO find a reliable metric for determining the activity of blobs...
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var blobCount = 0;
|
||||||
|
var lastHour = 0;
|
||||||
|
blobs.list.blobs(function (err, item, next) {
|
||||||
|
blobCount++;
|
||||||
|
if (err) {
|
||||||
|
Log.error("EVICT_BLOB_LIST_BLOBS_ERROR", err);
|
||||||
|
return void next();
|
||||||
|
}
|
||||||
|
if (pins[item.blobId]) { return void next(); }
|
||||||
|
if (item && getNewestTime(item) > retentionTime) { return void next(); }
|
||||||
|
// TODO determine when to retire blobs
|
||||||
|
console.log(item);
|
||||||
|
next();
|
||||||
|
}, w(function () {
|
||||||
|
console.log("Listed %s blobs", blobCount);
|
||||||
|
console.log("Listed %s blobs accessed in the last hour", lastHour);
|
||||||
|
}));
|
||||||
|
}).nThen(function (w) {
|
||||||
|
var proofCount = 0;
|
||||||
|
blobs.list.proofs(function (err, item, next) {
|
||||||
|
proofCount++;
|
||||||
|
if (err) {
|
||||||
|
next();
|
||||||
|
return void Log.error("EVICT_BLOB_LIST_PROOFS_ERROR", err);
|
||||||
|
}
|
||||||
|
if (pins[item.blobId]) { return void next(); }
|
||||||
|
if (item && getNewestTime(item) > retentionTime) { return void next(); }
|
||||||
|
nThen(function (w) {
|
||||||
|
blobs.size(item.blobId, w(function (err, size) {
|
||||||
|
if (err) {
|
||||||
|
w.abort();
|
||||||
|
next();
|
||||||
|
return void Log.error("EVICT_BLOB_LIST_PROOFS_ERROR", err);
|
||||||
|
}
|
||||||
|
if (size !== 0) {
|
||||||
|
w.abort();
|
||||||
|
next();
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}).nThen(function () {
|
||||||
|
blobs.remove.proof(item.safeKey, item.blobId, function (err) {
|
||||||
|
next();
|
||||||
|
if (err) {
|
||||||
|
return Log.error("EVICT_BLOB_PROOF_LONELY_ERROR", item);
|
||||||
|
}
|
||||||
|
return Log.info("EVICT_BLOB_PROOF_LONELY", item);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}, function () {
|
||||||
|
console.log("Listed %s blob proofs", proofCount);
|
||||||
|
});
|
||||||
|
*/
|
||||||
}).nThen(function (w) {
|
}).nThen(function (w) {
|
||||||
var removed = 0;
|
var removed = 0;
|
||||||
var channels = 0;
|
var channels = 0;
|
||||||
|
|||||||
@ -37,6 +37,14 @@ var makeProofPath = function (Env, safeKey, blobId) {
|
|||||||
return Path.join(Env.blobPath, safeKey.slice(0, 3), safeKey, blobId.slice(0, 2), blobId);
|
return Path.join(Env.blobPath, safeKey.slice(0, 3), safeKey, blobId.slice(0, 2), blobId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var parseProofPath = function (path) {
|
||||||
|
var parts = path.split('/');
|
||||||
|
return {
|
||||||
|
blobId: parts[parts.length -1],
|
||||||
|
safeKey: parts[parts.length - 3],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
// getUploadSize: used by
|
// getUploadSize: used by
|
||||||
// getFileSize
|
// getFileSize
|
||||||
var getUploadSize = function (Env, blobId, cb) {
|
var getUploadSize = function (Env, blobId, cb) {
|
||||||
@ -346,11 +354,11 @@ var restoreProof = function (Env, safeKey, blobId, cb) {
|
|||||||
Fse.move(archivePath, proofPath, cb);
|
Fse.move(archivePath, proofPath, cb);
|
||||||
};
|
};
|
||||||
|
|
||||||
var makeWalker = function (n, handleChild, cb) {
|
var makeWalker = function (n, handleChild, done) {
|
||||||
if (!n || typeof(n) !== 'number' || n < 2) { n = 2; }
|
if (!n || typeof(n) !== 'number' || n < 2) { n = 2; }
|
||||||
|
|
||||||
var W;
|
var W;
|
||||||
var nt = nThen(function (w) {
|
nThen(function (w) {
|
||||||
// this asynchronous bit defers the completion of this block until
|
// this asynchronous bit defers the completion of this block until
|
||||||
// synchronous execution has completed. This means you must create
|
// synchronous execution has completed. This means you must create
|
||||||
// the walker and start using it synchronously or else it will call back
|
// the walker and start using it synchronously or else it will call back
|
||||||
@ -358,7 +366,7 @@ var makeWalker = function (n, handleChild, cb) {
|
|||||||
setTimeout(w());
|
setTimeout(w());
|
||||||
W = w;
|
W = w;
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
cb();
|
done();
|
||||||
});
|
});
|
||||||
|
|
||||||
// do no more than 20 jobs at a time
|
// do no more than 20 jobs at a time
|
||||||
@ -366,21 +374,28 @@ var makeWalker = function (n, handleChild, cb) {
|
|||||||
|
|
||||||
var recurse = function (path) {
|
var recurse = function (path) {
|
||||||
tasks.take(function (give) {
|
tasks.take(function (give) {
|
||||||
var done = give(W());
|
var next = give(W());
|
||||||
Fs.readdir(path, function (err, dir) {
|
|
||||||
if (err) {
|
nThen(function (w) {
|
||||||
if (err.code === 'ENOTDIR') {
|
// check if the path is a directory...
|
||||||
return void handleChild(path, done);
|
Fs.stat(path, w(function (err, stats) {
|
||||||
|
if (err) { return next(); }
|
||||||
|
if (!stats.isDirectory()) {
|
||||||
|
w.abort();
|
||||||
|
return void handleChild(void 0, path, next);
|
||||||
}
|
}
|
||||||
// XXX handle other error
|
// fall through
|
||||||
return done();
|
}));
|
||||||
}
|
}).nThen(function () {
|
||||||
// everything is fine and it's a directory...
|
// handle directories
|
||||||
if (dir.length === 0) { return done(); }
|
Fs.readdir(path, function (err, dir) {
|
||||||
dir.forEach(function (d) {
|
if (err) { return next(); }
|
||||||
recurse(Path.join(path, d));
|
// everything is fine and it's a directory...
|
||||||
|
dir.forEach(function (d) {
|
||||||
|
recurse(Path.join(path, d));
|
||||||
|
});
|
||||||
|
next();
|
||||||
});
|
});
|
||||||
done();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -392,17 +407,28 @@ var listProofs = function (root, handler, cb) {
|
|||||||
Fs.readdir(root, function (err, dir) {
|
Fs.readdir(root, function (err, dir) {
|
||||||
if (err) { return void cb(err); }
|
if (err) { return void cb(err); }
|
||||||
|
|
||||||
var walk = makeWalker(20, function (path, next) {
|
var walk = makeWalker(20, function (err, path, next) {
|
||||||
// path is the path to a child node on the filesystem
|
// path is the path to a child node on the filesystem
|
||||||
|
|
||||||
// next handles the next job in a queue
|
// next handles the next job in a queue
|
||||||
|
|
||||||
// iterate over proofs
|
// iterate over proofs
|
||||||
// check for presence of corresponding files
|
// check for presence of corresponding files
|
||||||
|
Fs.stat(path, function (err, stats) {
|
||||||
|
if (err) {
|
||||||
|
return void handler(err, void 0, next);
|
||||||
|
}
|
||||||
|
|
||||||
handler(path, next);
|
var parsed = parseProofPath(path);
|
||||||
//console.log(path);
|
handler(void 0, {
|
||||||
//next();
|
path: path,
|
||||||
|
blobId: parsed.blobId,
|
||||||
|
safeKey: parsed.safeKey,
|
||||||
|
atime: stats.atime,
|
||||||
|
ctime: stats.ctime,
|
||||||
|
mtime: stats.mtime,
|
||||||
|
}, next);
|
||||||
|
});
|
||||||
}, function () {
|
}, function () {
|
||||||
// called when there are no more directories or children to process
|
// called when there are no more directories or children to process
|
||||||
cb();
|
cb();
|
||||||
@ -420,8 +446,19 @@ var listBlobs = function (root, handler, cb) {
|
|||||||
// iterate over files
|
// iterate over files
|
||||||
Fs.readdir(root, function (err, dir) {
|
Fs.readdir(root, function (err, dir) {
|
||||||
if (err) { return void cb(err); }
|
if (err) { return void cb(err); }
|
||||||
var walk = makeWalker(20, function (path, next) {
|
var walk = makeWalker(20, function (err, path, next) {
|
||||||
handler(path, next);
|
Fs.stat(path, function (err, stats) {
|
||||||
|
if (err) {
|
||||||
|
return void handler(err, void 0, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
handler(void 0, {
|
||||||
|
blobId: Path.basename(path),
|
||||||
|
atime: stats.atime,
|
||||||
|
ctime: stats.ctime,
|
||||||
|
mtime: stats.mtime,
|
||||||
|
}, next);
|
||||||
|
});
|
||||||
}, function () {
|
}, function () {
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user