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:
		
							
								
								
									
										26
									
								
								core/core.js
									
									
									
									
									
								
							
							
						
						
									
										26
									
								
								core/core.js
									
									
									
									
									
								
							| @@ -105,7 +105,7 @@ function databaseGetAll() { | ||||
| 	return getDatabase(this).getAll(); | ||||
| } | ||||
|  | ||||
| function getPackages() { | ||||
| async function getPackages() { | ||||
| 	var packages = []; | ||||
| 	var packageOwners = File.readDirectory("packages/"); | ||||
| 	for (var i = 0; i < packageOwners.length; i++) { | ||||
| @@ -116,7 +116,7 @@ function getPackages() { | ||||
| 					packages.push({ | ||||
| 						owner: packageOwners[i], | ||||
| 						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)); | ||||
| } | ||||
|  | ||||
| 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 lines = readFileUtf8(fileName).split("\n").map(x => x.trimRight()); | ||||
| 	for (let i = 0; i < lines.length; i++) { | ||||
| @@ -212,6 +222,12 @@ function getManifest(fileName) { | ||||
| 		print("ERROR: getManifest(" + fileName + "): ", error); | ||||
| 		// Oh well.  No manifest. | ||||
| 	} | ||||
|  | ||||
| 	gManifestCache[fileName] = { | ||||
| 		stat: stat, | ||||
| 		manifest: result, | ||||
| 	}; | ||||
|  | ||||
| 	return result; | ||||
| } | ||||
|  | ||||
| @@ -220,7 +236,7 @@ function packageNameToPath(name) { | ||||
| 	return "packages/" + process.packageOwner + "/" + name + "/"; | ||||
| } | ||||
|  | ||||
| function getProcess(packageOwner, packageName, key, options) { | ||||
| async function getProcess(packageOwner, packageName, key, options) { | ||||
| 	var process = gProcesses[key]; | ||||
| 	if (!process | ||||
| 		&& !(options && "create" in options && !options.create) | ||||
| @@ -229,7 +245,7 @@ function getProcess(packageOwner, packageName, key, options) { | ||||
| 		try { | ||||
| 			print("Creating task for " + packageName + " " + key); | ||||
| 			var fileName = "packages/" + packageOwner + "/" + packageName + "/" + packageName + ".js"; | ||||
| 			var manifest = getManifest(fileName); | ||||
| 			var manifest = await getManifest(fileName); | ||||
| 			process = {}; | ||||
| 			process.key = key; | ||||
| 			process.index = gProcessIndex++; | ||||
|   | ||||
| @@ -143,7 +143,7 @@ function socket(request, response, client) { | ||||
| 	} | ||||
| 	options.credentials = credentials; | ||||
|  | ||||
| 	response.onMessage = function(event) { | ||||
| 	response.onMessage = async function(event) { | ||||
| 		if (event.opCode == 0x1 || event.opCode == 0x2) { | ||||
| 			var message; | ||||
| 			try { | ||||
| @@ -164,7 +164,7 @@ function socket(request, response, client) { | ||||
| 				response.send(JSON.stringify({lines: [{action: "session", sessionId: sessionId, credentials: credentials}]}), 0x1); | ||||
|  | ||||
| 				options.terminalApi = message.terminalApi || []; | ||||
| 				process = getSessionProcess(packageOwner, packageName, sessionId, options); | ||||
| 				process = await getSessionProcess(packageOwner, packageName, sessionId, options); | ||||
| 				process.terminal.readOutput(function(message) { | ||||
| 					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; | ||||
|  | ||||
| 	if (badName(packageOwner) || badName(packageName)) { | ||||
| @@ -292,7 +292,7 @@ function handler(request, response, packageOwner, packageName, uri) { | ||||
| 				} | ||||
| 			} | ||||
| 		} else if (uri === "/submit") { | ||||
| 				var process = getServiceProcess(packageOwner, packageName, "submit"); | ||||
| 				var process = await getServiceProcess(packageOwner, packageName, "submit"); | ||||
| 				process.lastActive = Date.now(); | ||||
| 				return process.ready.then(function() { | ||||
| 					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") { | ||||
| 			var process = getServiceProcess(packageOwner, packageName, "atom"); | ||||
| 			var process = await getServiceProcess(packageOwner, packageName, "atom"); | ||||
| 			process.lastActive = Date.now(); | ||||
| 			return process.ready.then(function() { | ||||
| 				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 "Task.h" | ||||
| #include "TaskTryCatch.h" | ||||
|  | ||||
| #include <cstring> | ||||
| #include <fstream> | ||||
| @@ -14,6 +15,14 @@ | ||||
| #include <unistd.h> | ||||
| #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) { | ||||
| 	v8::Local<v8::ObjectTemplate> fileTemplate = v8::ObjectTemplate::New(isolate); | ||||
| 	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, "renameFile"), v8::FunctionTemplate::New(isolate, renameFile)); | ||||
| 	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); | ||||
| } | ||||
|  | ||||
| @@ -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); | ||||
| 	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> | ||||
|  | ||||
| typedef struct uv_fs_s uv_fs_t; | ||||
|  | ||||
| class File { | ||||
| public: | ||||
| 	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 unlinkFile(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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user