precompile on startup
This commit is contained in:
+90
-48
@@ -159,13 +159,14 @@ String preprocess_shared_unit_char_wise(Request* context, SharedUnit* su, String
|
||||
pc.append("#include \"" + sub_su->bin_path + "/" + sub_su->pre_file_name + "\"\n");
|
||||
}
|
||||
}
|
||||
else if(current_line.length() == 4 && current_line.substr(0, 4) == "API ")
|
||||
else if(false && current_line.substr(0, 6) == "EXPORT" && isspace(current_line[6]))
|
||||
{
|
||||
auto end_declaration_pos = content.find("{", i);
|
||||
if(end_declaration_pos != std::string::npos)
|
||||
{
|
||||
// remove string "API " from output
|
||||
pc.resize(pc.length() - 4);
|
||||
//pc.resize(pc.length() - 7);
|
||||
pc.append(1, '\n');
|
||||
String declaration = trim(content.substr(i, end_declaration_pos - i));
|
||||
String return_type_and_name = nibble(declaration, "(");
|
||||
StringList rtn_list = split_space(return_type_and_name);
|
||||
@@ -208,7 +209,7 @@ void setup_unit_paths(Request* context, SharedUnit* su, String file_name)
|
||||
su->pre_file_name = su->src_file_name + ".cpp";
|
||||
|
||||
su->so_name = su->bin_path + "/" + su->bin_file_name;
|
||||
su->api_file_name = su->bin_path + "/" + su->src_file_name + ".api.txt";
|
||||
su->api_file_name = su->bin_path + "/" + su->src_file_name + ".exports.txt";
|
||||
su->setup_file_name = su->bin_path + "/" + su->src_file_name + ".setup.h";
|
||||
}
|
||||
|
||||
@@ -224,7 +225,7 @@ void load_shared_unit(Request* context, SharedUnit* su, String file_name)
|
||||
{
|
||||
if(su->opt_so_optional)
|
||||
return;
|
||||
printf("(i) unit file not found: %s\n", su->so_name.c_str());
|
||||
//printf("(i) unit file not found: %s\n", su->so_name.c_str());
|
||||
su->compiler_messages = "unit file not found";
|
||||
return;
|
||||
}
|
||||
@@ -235,11 +236,11 @@ void load_shared_unit(Request* context, SharedUnit* su, String file_name)
|
||||
su->last_compiled = file_mtime(su->so_name);
|
||||
char *error;
|
||||
su->on_setup = (request_handler)dlsym(su->so_handle, "set_current_request");
|
||||
su->on_render = (call_handler)dlsym(su->so_handle, "render");
|
||||
if ((error = dlerror()) != NULL)
|
||||
printf("Error - %s in %s\n", error, su->file_name.c_str());
|
||||
else
|
||||
printf("(i) loaded unit %s\n", su->file_name.c_str());
|
||||
su->on_render = (call_handler)dlsym(su->so_handle, "render");
|
||||
//else
|
||||
// printf("(i) loaded unit %s\n", su->file_name.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -253,7 +254,7 @@ String compile_setup_file(Request* context, SharedUnit* su)
|
||||
String("#ifndef UCE_LIB_INCLUDED\n") +
|
||||
"#define UCE_LIB_INCLUDED\n" +
|
||||
("#include \"")+context->server->config.COMPILER_SYS_PATH +"/src/lib/uce_lib.h\" \n"+
|
||||
file_get_contents(context->server->config.SETUP_TEMPLATE) +
|
||||
file_get_contents(context->server->config.COMPILER_SYS_PATH + "/" + context->server->config.SETUP_TEMPLATE) +
|
||||
"#endif \n";
|
||||
StringList declarations;
|
||||
StringList load_units;
|
||||
@@ -296,7 +297,7 @@ void compile_shared_unit(Request* context, SharedUnit* su, String file_name)
|
||||
else
|
||||
{
|
||||
load_shared_unit(context, su, file_name);
|
||||
printf("(i) compiled unit %s\n", file_name.c_str());
|
||||
//printf("(i) compiled unit %s\n", file_name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -356,52 +357,18 @@ SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_opti
|
||||
return(su);
|
||||
}
|
||||
|
||||
void compiler_invoke(Request* context, String file_name, DTree& call_param)
|
||||
{
|
||||
|
||||
if(file_name[0] != '/')
|
||||
{
|
||||
file_name = expand_path(file_name);
|
||||
}
|
||||
//printf("(i) invoke %s\n", file_name.c_str());
|
||||
|
||||
//printf("(i) invoke(%s)\n", file_name.c_str());
|
||||
switch_to_system_alloc();
|
||||
auto su = get_shared_unit(context, file_name);
|
||||
switch_to_arena(context->mem);
|
||||
if(!su)
|
||||
{
|
||||
printf("Error loading unit %s\n", file_name.c_str());
|
||||
print("Error loading unit: "+file_name);
|
||||
}
|
||||
else if(su->compiler_messages.length() > 0)
|
||||
{
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print(su->compiler_messages);
|
||||
}
|
||||
else if(!su->on_render)
|
||||
{
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print("no RENDER() entry point");
|
||||
}
|
||||
else
|
||||
{
|
||||
String prev_wd = get_cwd();
|
||||
set_cwd(su->src_path);
|
||||
su->on_setup(context);
|
||||
su->on_render(call_param);
|
||||
set_cwd(prev_wd);
|
||||
}
|
||||
}
|
||||
|
||||
SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String current_path, bool opt_so_optional)
|
||||
{
|
||||
|
||||
context->stats.invoke_count++;
|
||||
|
||||
if(file_name[0] != '/')
|
||||
{
|
||||
file_name = expand_path(file_name, current_path);
|
||||
}
|
||||
|
||||
//printf("(i) load '%s'\n", file_name.c_str());
|
||||
|
||||
switch_to_system_alloc();
|
||||
auto su = get_shared_unit(context, file_name, opt_so_optional);
|
||||
switch_to_arena(context->mem);
|
||||
@@ -413,7 +380,8 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
|
||||
}
|
||||
else if(su->compiler_messages.length() > 0)
|
||||
{
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
if(context->stats.invoke_count == 1)
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print(su->compiler_messages);
|
||||
return(0);
|
||||
}
|
||||
@@ -424,3 +392,77 @@ SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String
|
||||
|
||||
}
|
||||
|
||||
void compiler_invoke(Request* context, String file_name, DTree& call_param)
|
||||
{
|
||||
auto su = compiler_load_shared_unit(context, file_name, "", false);
|
||||
if(su)
|
||||
{
|
||||
if(!su->on_setup)
|
||||
{
|
||||
if(context->stats.invoke_count == 1)
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print("internal error: set_current_request() not defined in", file_name, "\n");
|
||||
}
|
||||
else if(!su->on_render)
|
||||
{
|
||||
if(context->stats.invoke_count == 1)
|
||||
context->header["Content-Type"] = "text/plain";
|
||||
print("no RENDER() entry point");
|
||||
}
|
||||
else
|
||||
{
|
||||
String prev_wd = get_cwd();
|
||||
set_cwd(su->src_path);
|
||||
su->on_setup(context);
|
||||
su->on_render(call_param);
|
||||
set_cwd(prev_wd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void render_file(String file_name)
|
||||
{
|
||||
//printf("(i) render_file(%s)\n", file_name.c_str());
|
||||
DTree call_param;
|
||||
compiler_invoke(context, file_name, call_param);
|
||||
}
|
||||
|
||||
void render_file(String file_name, DTree& call_param)
|
||||
{
|
||||
compiler_invoke(context, file_name, call_param);
|
||||
}
|
||||
|
||||
DTree* call_file_function(String file_name, String function_name, DTree* call_param)
|
||||
{
|
||||
DTree* result;
|
||||
auto su = compiler_load_shared_unit(context, file_name, "", false);
|
||||
if(su && su->so_handle)
|
||||
{
|
||||
if(!su->on_setup)
|
||||
{
|
||||
print("internal error: set_current_request() not defined in", file_name, "\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto f = (dtree_call_handler)dlsym(su->so_handle, function_name.c_str());
|
||||
if(!f)
|
||||
{
|
||||
print("Error: call_file_function() function '", function_name, "' not found");
|
||||
}
|
||||
else
|
||||
{
|
||||
String prev_wd = get_cwd();
|
||||
set_cwd(su->src_path);
|
||||
su->on_setup(context);
|
||||
result = f(call_param);
|
||||
set_cwd(prev_wd);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
print("Error: call_file_function() could not load unit file '", file_name, "'");
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#define RENDER() extern "C" void render(DTree& call)
|
||||
#define EXPORT extern "C"
|
||||
|
||||
String process_html_literal(Request* context, SharedUnit* su, String content);
|
||||
String preprocess_shared_unit(Request* context, SharedUnit* su);
|
||||
@@ -8,3 +9,9 @@ void compile_shared_unit(Request* context, SharedUnit* su, String file_name);
|
||||
SharedUnit* get_shared_unit(Request* context, String file_name, bool opt_so_optional = false);
|
||||
void compiler_invoke(Request* context, String file_name, DTree& call_param);
|
||||
SharedUnit* compiler_load_shared_unit(Request* context, String file_name, String current_path, bool opt_so_optional = false);
|
||||
|
||||
void render_file(String file_name);
|
||||
void render_file(String file_name, DTree& call_param);
|
||||
DTree* call_file_function(String file_name, String function_name, DTree* call_param = 0);
|
||||
|
||||
StringList precompile_jobs;
|
||||
|
||||
@@ -533,3 +533,13 @@ String ob_get_close()
|
||||
return(result);
|
||||
}
|
||||
|
||||
String safe_name(String raw)
|
||||
{
|
||||
String result = "";
|
||||
for(auto c : raw)
|
||||
{
|
||||
if(isalnum(c) || c == '_')
|
||||
result.append(1, c);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
@@ -60,5 +60,6 @@ void ob_start();
|
||||
void ob_clear();
|
||||
String ob_get_clear();
|
||||
String ob_get();
|
||||
String safe_name(String raw);
|
||||
|
||||
#define is_bit_set(var,pos) ((var) & (1<<(pos)))
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@
|
||||
|
||||
String shell_exec(String cmd)
|
||||
{
|
||||
printf("(i) shell_exec(%s)\n", cmd.c_str());
|
||||
//printf("(i) shell_exec(%s)\n", cmd.c_str());
|
||||
String data;
|
||||
FILE * stream;
|
||||
const int max_buffer = 256;
|
||||
|
||||
@@ -39,6 +39,7 @@ String nibble(String div, String& haystack)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void Request::invoke(String file_name)
|
||||
{
|
||||
DTree call_param;
|
||||
@@ -50,6 +51,8 @@ void Request::invoke(String file_name, DTree& call_param)
|
||||
compiler_invoke(this, file_name, call_param);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
void Request::ob_start()
|
||||
{
|
||||
ob_stack.push_back(new std::ostringstream());
|
||||
@@ -61,3 +64,4 @@ Request::~Request()
|
||||
for(auto& sockfd : resources.sockets)
|
||||
close(sockfd);
|
||||
}
|
||||
|
||||
|
||||
+6
-2
@@ -141,6 +141,7 @@ struct Request;
|
||||
struct DTree;
|
||||
|
||||
typedef void (*call_handler)(DTree& call_param);
|
||||
typedef DTree* (*dtree_call_handler)(DTree* call_param);
|
||||
typedef void (*request_handler)(Request* request);
|
||||
|
||||
String to_string(s64 v) { return(std::to_string(v)); }
|
||||
@@ -156,6 +157,8 @@ struct ServerSettings {
|
||||
String TMP_UPLOAD_PATH = "/tmp/uce/uploads";
|
||||
String SESSION_PATH = "/tmp/uce/sessions";
|
||||
String COMPILER_SYS_PATH = ".";
|
||||
String PRECOMPILE_FILES_IN = ".";
|
||||
|
||||
u32 LISTEN_PORT = 9993;
|
||||
u64 SESSION_TIME = 60*60*24*30;
|
||||
u32 WORKER_COUNT = 4;
|
||||
@@ -260,6 +263,7 @@ struct Request {
|
||||
f64 time_init;
|
||||
f64 time_start;
|
||||
f64 time_end;
|
||||
u32 invoke_count = 0;
|
||||
} stats;
|
||||
|
||||
struct Resources {
|
||||
@@ -268,8 +272,8 @@ struct Request {
|
||||
u64 fcgi_socket = 0;
|
||||
} resources;
|
||||
|
||||
void invoke(String file_name);
|
||||
void invoke(String file_name, DTree& call_param);
|
||||
//void invoke(String file_name);
|
||||
//void invoke(String file_name, DTree& call_param);
|
||||
|
||||
void ob_start();
|
||||
|
||||
|
||||
+45
-1
@@ -70,7 +70,7 @@ int handle_complete(FastCGIRequest& request) {
|
||||
}
|
||||
|
||||
// printf("(i) request ready\n");
|
||||
request.invoke(request.params["SCRIPT_FILENAME"]);
|
||||
render_file(request.params["SCRIPT_FILENAME"]);
|
||||
|
||||
for( auto &f : request.uploaded_files)
|
||||
{
|
||||
@@ -87,6 +87,17 @@ int handle_complete(FastCGIRequest& request) {
|
||||
|
||||
void listen_for_connections()
|
||||
{
|
||||
if(precompile_jobs.size() > 0)
|
||||
{
|
||||
context = new Request();
|
||||
context->server = &server_state;
|
||||
for(auto s : precompile_jobs)
|
||||
{
|
||||
printf("- worker [%i] precompile %s\n", getpid(), s.c_str());
|
||||
get_shared_unit(context, s, false);
|
||||
}
|
||||
}
|
||||
|
||||
signal(SIGSEGV, on_segfault);
|
||||
server.on_request = &handle_request;
|
||||
server.on_data = &handle_data;
|
||||
@@ -106,6 +117,9 @@ void listen_for_connections()
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
StringList precompile_jobs_pending;
|
||||
u32 precompile_jobs_per_worker = 1;
|
||||
|
||||
printf("(P) Starting parent server PID:%i\n", getpid());
|
||||
|
||||
signal(SIGCHLD, on_child_exit);
|
||||
@@ -143,11 +157,41 @@ int main(int argc, char** argv)
|
||||
{
|
||||
std::cout << e.what();
|
||||
}*/
|
||||
if(server_state.config.PRECOMPILE_FILES_IN != "" && server_state.config.WORKER_COUNT >= 2)
|
||||
{
|
||||
if(server_state.config.PRECOMPILE_FILES_IN != "/")
|
||||
server_state.config.PRECOMPILE_FILES_IN = expand_path(server_state.config.PRECOMPILE_FILES_IN);
|
||||
precompile_jobs_pending = split(trim(shell_exec(
|
||||
"find " +
|
||||
shell_escape(server_state.config.PRECOMPILE_FILES_IN) +
|
||||
" -iname '*.uce' ")), "\n");
|
||||
precompile_jobs_per_worker = 1 + (precompile_jobs_pending.size() / (server_state.config.WORKER_COUNT -1));
|
||||
/*
|
||||
*/
|
||||
}
|
||||
|
||||
s32 worker_spawn_count = 0;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
while(workers.size() < server_state.config.WORKER_COUNT)
|
||||
{
|
||||
worker_spawn_count++;
|
||||
precompile_jobs.clear();
|
||||
// spawn workers with precompile jobs if necessary but
|
||||
// leave the first worker alone so it can start responding
|
||||
// to requests right away
|
||||
if(precompile_jobs_pending.size() > 0 && worker_spawn_count > 1)
|
||||
{
|
||||
for(u32 i = 0; i < precompile_jobs_per_worker; i++)
|
||||
{
|
||||
if(precompile_jobs_pending.size() > 0)
|
||||
{
|
||||
precompile_jobs.push_back(precompile_jobs_pending.back());
|
||||
precompile_jobs_pending.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
spawn_subprocess(listen_for_connections);
|
||||
}
|
||||
sleep(1);
|
||||
|
||||
Reference in New Issue
Block a user