Add File.stat. Use it to cache manifests to speed up task start. async spreads like a virus.
git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3377 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
parent
63361ec1f8
commit
c1b75821bf
26
core/core.js
26
core/core.js
@ -105,7 +105,7 @@ function databaseGetAll() {
|
|||||||
return getDatabase(this).getAll();
|
return getDatabase(this).getAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getPackages() {
|
async function getPackages() {
|
||||||
var packages = [];
|
var packages = [];
|
||||||
var packageOwners = File.readDirectory("packages/");
|
var packageOwners = File.readDirectory("packages/");
|
||||||
for (var i = 0; i < packageOwners.length; i++) {
|
for (var i = 0; i < packageOwners.length; i++) {
|
||||||
@ -116,7 +116,7 @@ function getPackages() {
|
|||||||
packages.push({
|
packages.push({
|
||||||
owner: packageOwners[i],
|
owner: packageOwners[i],
|
||||||
name: packageNames[j],
|
name: packageNames[j],
|
||||||
manifest: getManifest("packages/" + packageOwners[i] + "/" + packageNames[j] + "/" + packageNames[j] + ".js"),
|
manifest: await getManifest("packages/" + packageOwners[i] + "/" + packageNames[j] + "/" + packageNames[j] + ".js"),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -195,7 +195,17 @@ function readFileUtf8(fileName) {
|
|||||||
return new TextDecoder("UTF-8").decode(File.readFile(fileName));
|
return new TextDecoder("UTF-8").decode(File.readFile(fileName));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getManifest(fileName) {
|
let gManifestCache = {};
|
||||||
|
|
||||||
|
async function getManifest(fileName) {
|
||||||
|
let oldEntry = gManifestCache[fileName];
|
||||||
|
let stat = await File.stat(fileName);
|
||||||
|
if (oldEntry) {
|
||||||
|
if (oldEntry.stat.mtime == stat.mtime && oldEntry.stat.size == stat.size) {
|
||||||
|
return oldEntry.manifest;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let manifest = [];
|
let manifest = [];
|
||||||
let lines = readFileUtf8(fileName).split("\n").map(x => x.trimRight());
|
let lines = readFileUtf8(fileName).split("\n").map(x => x.trimRight());
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
@ -212,6 +222,12 @@ function getManifest(fileName) {
|
|||||||
print("ERROR: getManifest(" + fileName + "): ", error);
|
print("ERROR: getManifest(" + fileName + "): ", error);
|
||||||
// Oh well. No manifest.
|
// Oh well. No manifest.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gManifestCache[fileName] = {
|
||||||
|
stat: stat,
|
||||||
|
manifest: result,
|
||||||
|
};
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +236,7 @@ function packageNameToPath(name) {
|
|||||||
return "packages/" + process.packageOwner + "/" + name + "/";
|
return "packages/" + process.packageOwner + "/" + name + "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
function getProcess(packageOwner, packageName, key, options) {
|
async function getProcess(packageOwner, packageName, key, options) {
|
||||||
var process = gProcesses[key];
|
var process = gProcesses[key];
|
||||||
if (!process
|
if (!process
|
||||||
&& !(options && "create" in options && !options.create)
|
&& !(options && "create" in options && !options.create)
|
||||||
@ -229,7 +245,7 @@ function getProcess(packageOwner, packageName, key, options) {
|
|||||||
try {
|
try {
|
||||||
print("Creating task for " + packageName + " " + key);
|
print("Creating task for " + packageName + " " + key);
|
||||||
var fileName = "packages/" + packageOwner + "/" + packageName + "/" + packageName + ".js";
|
var fileName = "packages/" + packageOwner + "/" + packageName + "/" + packageName + ".js";
|
||||||
var manifest = getManifest(fileName);
|
var manifest = await getManifest(fileName);
|
||||||
process = {};
|
process = {};
|
||||||
process.key = key;
|
process.key = key;
|
||||||
process.index = gProcessIndex++;
|
process.index = gProcessIndex++;
|
||||||
|
@ -143,7 +143,7 @@ function socket(request, response, client) {
|
|||||||
}
|
}
|
||||||
options.credentials = credentials;
|
options.credentials = credentials;
|
||||||
|
|
||||||
response.onMessage = function(event) {
|
response.onMessage = async function(event) {
|
||||||
if (event.opCode == 0x1 || event.opCode == 0x2) {
|
if (event.opCode == 0x1 || event.opCode == 0x2) {
|
||||||
var message;
|
var message;
|
||||||
try {
|
try {
|
||||||
@ -164,7 +164,7 @@ function socket(request, response, client) {
|
|||||||
response.send(JSON.stringify({lines: [{action: "session", sessionId: sessionId, credentials: credentials}]}), 0x1);
|
response.send(JSON.stringify({lines: [{action: "session", sessionId: sessionId, credentials: credentials}]}), 0x1);
|
||||||
|
|
||||||
options.terminalApi = message.terminalApi || [];
|
options.terminalApi = message.terminalApi || [];
|
||||||
process = getSessionProcess(packageOwner, packageName, sessionId, options);
|
process = await getSessionProcess(packageOwner, packageName, sessionId, options);
|
||||||
process.terminal.readOutput(function(message) {
|
process.terminal.readOutput(function(message) {
|
||||||
response.send(JSON.stringify(message), 0x1);
|
response.send(JSON.stringify(message), 0x1);
|
||||||
});
|
});
|
||||||
@ -226,7 +226,7 @@ function socket(request, response, client) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handler(request, response, packageOwner, packageName, uri) {
|
async function handler(request, response, packageOwner, packageName, uri) {
|
||||||
var found = false;
|
var found = false;
|
||||||
|
|
||||||
if (badName(packageOwner) || badName(packageName)) {
|
if (badName(packageOwner) || badName(packageName)) {
|
||||||
@ -292,7 +292,7 @@ function handler(request, response, packageOwner, packageName, uri) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (uri === "/submit") {
|
} else if (uri === "/submit") {
|
||||||
var process = getServiceProcess(packageOwner, packageName, "submit");
|
var process = await getServiceProcess(packageOwner, packageName, "submit");
|
||||||
process.lastActive = Date.now();
|
process.lastActive = Date.now();
|
||||||
return process.ready.then(function() {
|
return process.ready.then(function() {
|
||||||
var payload = form.decodeForm(request.body, form.decodeForm(request.query));
|
var payload = form.decodeForm(request.body, form.decodeForm(request.query));
|
||||||
@ -308,7 +308,7 @@ function handler(request, response, packageOwner, packageName, uri) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
} else if (uri === "/atom") {
|
} else if (uri === "/atom") {
|
||||||
var process = getServiceProcess(packageOwner, packageName, "atom");
|
var process = await getServiceProcess(packageOwner, packageName, "atom");
|
||||||
process.lastActive = Date.now();
|
process.lastActive = Date.now();
|
||||||
return process.ready.then(function() {
|
return process.ready.then(function() {
|
||||||
var payload = form.decodeForm(request.body, form.decodeForm(request.query));
|
var payload = form.decodeForm(request.body, form.decodeForm(request.query));
|
||||||
|
55
src/File.cpp
55
src/File.cpp
@ -1,6 +1,7 @@
|
|||||||
#include "File.h"
|
#include "File.h"
|
||||||
|
|
||||||
#include "Task.h"
|
#include "Task.h"
|
||||||
|
#include "TaskTryCatch.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
@ -14,6 +15,14 @@
|
|||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
double timeSpecToDouble(uv_timespec_t& timeSpec);
|
||||||
|
|
||||||
|
struct FileStatData {
|
||||||
|
Task* _task;
|
||||||
|
promiseid_t _promise;
|
||||||
|
uv_fs_t _request;
|
||||||
|
};
|
||||||
|
|
||||||
void File::configure(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> global) {
|
void File::configure(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> global) {
|
||||||
v8::Local<v8::ObjectTemplate> fileTemplate = v8::ObjectTemplate::New(isolate);
|
v8::Local<v8::ObjectTemplate> fileTemplate = v8::ObjectTemplate::New(isolate);
|
||||||
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "readFile"), v8::FunctionTemplate::New(isolate, readFile));
|
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "readFile"), v8::FunctionTemplate::New(isolate, readFile));
|
||||||
@ -22,6 +31,7 @@ void File::configure(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> global
|
|||||||
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "writeFile"), v8::FunctionTemplate::New(isolate, writeFile));
|
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "writeFile"), v8::FunctionTemplate::New(isolate, writeFile));
|
||||||
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "renameFile"), v8::FunctionTemplate::New(isolate, renameFile));
|
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "renameFile"), v8::FunctionTemplate::New(isolate, renameFile));
|
||||||
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "unlinkFile"), v8::FunctionTemplate::New(isolate, unlinkFile));
|
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "unlinkFile"), v8::FunctionTemplate::New(isolate, unlinkFile));
|
||||||
|
fileTemplate->Set(v8::String::NewFromUtf8(isolate, "stat"), v8::FunctionTemplate::New(isolate, stat));
|
||||||
global->Set(v8::String::NewFromUtf8(isolate, "File"), fileTemplate);
|
global->Set(v8::String::NewFromUtf8(isolate, "File"), fileTemplate);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,3 +144,48 @@ void File::makeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
|||||||
int result = uv_fs_mkdir(task->getLoop(), &req, *v8::String::Utf8Value(directory), 0755, 0);
|
int result = uv_fs_mkdir(task->getLoop(), &req, *v8::String::Utf8Value(directory), 0755, 0);
|
||||||
args.GetReturnValue().Set(result);
|
args.GetReturnValue().Set(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void File::stat(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||||
|
if (Task* task = Task::get(args.GetIsolate())) {
|
||||||
|
v8::HandleScope scope(args.GetIsolate());
|
||||||
|
v8::Handle<v8::String> path = args[0]->ToString();
|
||||||
|
|
||||||
|
promiseid_t promise = task->allocatePromise();
|
||||||
|
|
||||||
|
FileStatData* data = new FileStatData;
|
||||||
|
data->_task = task;
|
||||||
|
data->_promise = promise;
|
||||||
|
data->_request.data = data;
|
||||||
|
|
||||||
|
int result = uv_fs_stat(task->getLoop(), &data->_request, *v8::String::Utf8Value(path), onStatComplete);
|
||||||
|
if (result) {
|
||||||
|
task->resolvePromise(promise, v8::Number::New(args.GetIsolate(), result));
|
||||||
|
delete data;
|
||||||
|
}
|
||||||
|
args.GetReturnValue().Set(task->getPromise(promise));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double timeSpecToDouble(uv_timespec_t& timeSpec) {
|
||||||
|
return timeSpec.tv_sec + static_cast<double>(timeSpec.tv_nsec) / 1e9;
|
||||||
|
}
|
||||||
|
|
||||||
|
void File::onStatComplete(uv_fs_t* request) {
|
||||||
|
FileStatData* data = reinterpret_cast<FileStatData*>(request->data);
|
||||||
|
v8::EscapableHandleScope scope(data->_task->getIsolate());
|
||||||
|
TaskTryCatch tryCatch(data->_task);
|
||||||
|
v8::Isolate* isolate = data->_task->getIsolate();
|
||||||
|
v8::Context::Scope contextScope(v8::Local<v8::Context>::New(isolate, data->_task->getContext()));
|
||||||
|
|
||||||
|
if (request->result) {
|
||||||
|
data->_task->rejectPromise(data->_promise, v8::Number::New(data->_task->getIsolate(), request->result));
|
||||||
|
} else {
|
||||||
|
v8::Handle<v8::Object> result = v8::Object::New(isolate);
|
||||||
|
result->Set(v8::String::NewFromUtf8(isolate, "mtime"), v8::Number::New(isolate, timeSpecToDouble(request->statbuf.st_mtim)));
|
||||||
|
result->Set(v8::String::NewFromUtf8(isolate, "ctime"), v8::Number::New(isolate, timeSpecToDouble(request->statbuf.st_ctim)));
|
||||||
|
result->Set(v8::String::NewFromUtf8(isolate, "atime"), v8::Number::New(isolate, timeSpecToDouble(request->statbuf.st_atim)));
|
||||||
|
result->Set(v8::String::NewFromUtf8(isolate, "size"), v8::Number::New(isolate, request->statbuf.st_size));
|
||||||
|
data->_task->resolvePromise(data->_promise, result);
|
||||||
|
}
|
||||||
|
delete data;
|
||||||
|
}
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <v8.h>
|
#include <v8.h>
|
||||||
|
|
||||||
|
typedef struct uv_fs_s uv_fs_t;
|
||||||
|
|
||||||
class File {
|
class File {
|
||||||
public:
|
public:
|
||||||
static void configure(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> global);
|
static void configure(v8::Isolate* isolate, v8::Handle<v8::ObjectTemplate> global);
|
||||||
@ -14,6 +16,9 @@ private:
|
|||||||
static void makeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void makeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void unlinkFile(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void unlinkFile(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
static void renameFile(const v8::FunctionCallbackInfo<v8::Value>& args);
|
static void renameFile(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
static void stat(const v8::FunctionCallbackInfo<v8::Value>& args);
|
||||||
|
|
||||||
|
static void onStatComplete(uv_fs_t* request);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user