From 46844bb71720bbc033e5348091bd2ab80570e31c Mon Sep 17 00:00:00 2001 From: rswindell <> Date: Sun, 29 Mar 2020 08:01:59 +0000 Subject: [PATCH] Add system.get_node() method to read a single node record in one shot: use this in place of system.node_list[] if you're going to be using a lot of the properties and passing them around to methods which are going to each possibly dereference the values, as *each* deference results in a read of the node record in the node.dab. On my system, a simple node list (e.g. /L command) would result in between 60 and 100 reads of the node.dab (for a 13 node system), which was nuts. The system.get_node() method currently leaves the node record unlocked and there is currently no equivalent put_node() method, so you still need to use the system.node_list[] for modification of node records. But, I now see there are race conditions with the current methods of read-modify-writes of the node_list[] properties. We should be locking a node.dab record, reading it, modifying it, writing it, and then unlocking it - as is done in the C/C++ code. So... that's a todo item. Also created system.stats.node_gets to track the number of node.dab reads from a single instance of the system object. May remove this any time. --- src/sbbs3/js_system.c | 64 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 63 insertions(+), 1 deletion(-) diff --git a/src/sbbs3/js_system.c b/src/sbbs3/js_system.c index c3ef9f57c9..3cf5c30364 100644 --- a/src/sbbs3/js_system.c +++ b/src/sbbs3/js_system.c @@ -42,6 +42,7 @@ typedef struct { scfg_t* cfg; int nodefile; + int nodegets; } js_system_private_t; extern JSClass js_system_class; @@ -564,6 +565,8 @@ enum { ,SYSSTAT_PROP_TOTALMSGS ,SYSSTAT_PROP_TOTALMAIL ,SYSSTAT_PROP_FEEDBACK + + ,SYSSTAT_PROP_NODE_GETS }; #ifndef JSDOOR @@ -665,6 +668,10 @@ static JSBool js_sysstats_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) *vp = INT_TO_JSVAL(getmail(cfg, /* user: */1, /* Sent: */FALSE, /* SPAM: */FALSE)); JS_RESUMEREQUEST(cx, rc); break; + + case SYSSTAT_PROP_NODE_GETS: + *vp = INT_TO_JSVAL(sys->nodegets); + break; } return(TRUE); @@ -692,6 +699,7 @@ static jsSyncPropertySpec js_sysstats_properties[] = { { "feedback_sent_today", SYSSTAT_PROP_FTODAY, SYSSTAT_FLAGS, 310 }, { "total_users", SYSSTAT_PROP_TOTALUSERS, SYSSTAT_FLAGS, 310 }, { "new_users_today", SYSSTAT_PROP_NUSERS, SYSSTAT_FLAGS, 310 }, + { "node_gets", SYSSTAT_PROP_NODE_GETS, JSPROP_READONLY, 31702 }, {0} }; @@ -1384,6 +1392,54 @@ js_filter_ip(JSContext *cx, uintN argc, jsval *arglist) return(JS_TRUE); } +static JSBool +js_get_node(JSContext *cx, uintN argc, jsval *arglist) +{ + JSObject* obj=JS_THIS_OBJECT(cx, arglist); + JSObject* nodeobj; + jsval* argv=JS_ARGV(cx, arglist); + node_t node = {0}; + int32 node_num; + jsrefcount rc; + + JS_SET_RVAL(cx, arglist, JSVAL_NULL); + + js_system_private_t* sys; + if((sys = (js_system_private_t*)js_GetClassPrivate(cx,obj,&js_system_class))==NULL) + return JS_FALSE; + scfg_t* cfg = sys->cfg; + + node_num=cfg->node_num; + if(argc) + JS_ValueToInt32(cx,argv[0],&node_num); + if(node_num<1) + node_num=1; + + rc=JS_SUSPENDREQUEST(cx); + + int retval = getnodedat(sys->cfg, node_num, &node, /* lockit: */FALSE, &sys->nodefile); + sys->nodegets++; + JS_RESUMEREQUEST(cx, rc); + if(retval != 0) { + JS_ReportError(cx, "getnodat(%d) returned %d", node_num, retval); + return JS_TRUE; + } + if((nodeobj = JS_NewObject(cx, NULL, NULL, obj)) == NULL) { + JS_ReportError(cx, "JS_NewObject failure"); + return JS_TRUE; + } + JS_DefineProperty(cx, nodeobj, "status", INT_TO_JSVAL((int)node.status), NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(cx, nodeobj, "errors", INT_TO_JSVAL((int)node.errors), NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(cx, nodeobj, "action", INT_TO_JSVAL((int)node.action), NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(cx, nodeobj, "useron", INT_TO_JSVAL((int)node.useron), NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(cx, nodeobj, "connection", INT_TO_JSVAL((int)node.connection), NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(cx, nodeobj, "misc", INT_TO_JSVAL((int)node.misc), NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(cx, nodeobj, "aux", INT_TO_JSVAL((int)node.aux), NULL, NULL, JSPROP_ENUMERATE); + JS_DefineProperty(cx, nodeobj, "extaux", INT_TO_JSVAL((int)node.extaux), NULL, NULL, JSPROP_ENUMERATE); + JS_SET_RVAL(cx, arglist, OBJECT_TO_JSVAL(nodeobj)); + return JS_TRUE; +} + static JSBool js_get_node_message(JSContext *cx, uintN argc, jsval *arglist) { @@ -1908,7 +1964,12 @@ static jsSyncMethodSpec js_system_functions[] = { {"filter_ip", js_filter_ip, 4, JSTYPE_BOOLEAN, JSDOCSTR("[protocol, reason, host, ip, username, filename]") ,JSDOCSTR("add an IP address (with comment) to an IP filter file. If filename is not specified, the ip.can file is used") ,311 - }, + }, + {"get_node", js_get_node, 1, JSTYPE_OBJECT, JSDOCSTR("node_number") + ,JSDOCSTR("read a node data record all at once (and leaving the record unlocked) " + "returning an object matching the elements of <tt>system.node_list</tt>") + ,31702 + }, {"get_node_message",js_get_node_message,0, JSTYPE_STRING, JSDOCSTR("node_number") ,JSDOCSTR("read any messages waiting for the specified node and return in a single string") ,311 @@ -2034,6 +2095,7 @@ static JSBool js_node_get(JSContext *cx, JSObject *obj, jsid id, jsval *vp) return(JS_TRUE); } JS_RESUMEREQUEST(cx, rc); + sys->nodegets++; switch(tiny) { case NODE_PROP_STATUS: -- GitLab