Obsolete /
GDPJSNotesThis page contains old and obsolete notes about the GDP JavaScript Interface. See GDP JS for more recent information. OverviewThis page is about using a C-based, Node.js interface between the GDP and JavaScript. An alternative would be to write a GDP JavaScript Interface that uses the GDP wire protocol. The C-based code is in
See AlsoNotes about getting it to workGet access to the gdp repoAsk Eric Allman for access to the gdp repo. Build the gdpgit clone https://repo.eecs.berkeley.edu/git/projects/swarmlab/gdp.git cd gdp make If make does not work, then read the gdp sudo -i port install libevent sudo -i port install jansson Start up gdp_router and gdplogdTo run the [cxh@terra gdp]$ test/setupAndRun.sh #### test/setupAndRun.sh: Running git pull in /home/cxh/src/gdp_router Username for 'https://repo.eecs.berkeley.edu': cxh Password for 'https://cxh@repo.eecs.berkeley.edu': Already up-to-date. #### test/setupAndRun.sh: Removing /home/cxh/src/gcls and then recreating it. #### test/setupAndRun.sh: Set up /home/cxh/src/ep_adm_params To run with these settings from the command line, use: export EP_PARAM_PATH=/home/cxh/src/ep_adm_params #### test/setupAndRun.sh: Starting gdp_router Usage: pkill [-SIGNAL] [-fvx] [-n|-o] [-P PPIDLIST] [-g PGRPLIST] [-s SIDLIST] [-u EUIDLIST] [-U UIDLIST] [-G GIDLIST] [-t TERMLIST] [PATTERN] Command to start gdp_router (cd /home/cxh/src/gdp_router; python ./src/gdp_router.py -l routerLog.txt) & #### test/setupAndRun.sh: Starting gdplogd Command to start gdplogd: /home/cxh/src/gdp/gdplogd/gdplogd -F -N terra.EECS.Berkeley.EDU & My GDP routing name = terra.EECS.Berkeley.EDU #### Creating log gdp.runTests.27670 Command to create a log: /home/cxh/src/gdp/apps/gcl-create -k none -s terra.EECS.Berkeley.EDU gdp.runTests.27670 Created new GCL HNPCaXrzeP_5mP0TPHqu99exCbT4oAIzTih65HlyIUk on log server terra.EECS.Berkeley.EDU exiting with status OK test/setupAndRun.sh: called with no arguments, gdp daemons running: cxh 24481 1.6 0.0 212620 16032 pts/1 S+ 08:46 0:00 python ./src/gdp_router.py -l routerLog.txt cxh 24487 0.0 0.0 181252 2032 pts/1 Sl+ 08:46 0:00 /home/cxh/src/gdp/gdplogd/gdplogd -F -N terra.EECS.Berkeley.EDU cxh 24497 0.0 0.0 103320 864 pts/1 S+ 08:46 0:00 grep gdp test/setupAndRun.sh: Sleeping... C-c C-z [1]+ Stopped test/setupAndRun.sh [cxh@terra gdp]$ bg [1]+ test/setupAndRun.sh & [cxh@terra gdp]$ Optionally, check that the gdp processes are running: cxh@terra gdp]$ ps auxgwww | grep gdp cxh 24481 0.1 0.0 212620 16032 pts/1 S 08:46 0:00 python ./src/gdp_router.py -l routerLog.txt cxh 24487 0.0 0.0 181252 2032 pts/1 Sl 08:46 0:00 /home/cxh/src/gdp/gdplogd/gdplogd -F -N terra.EECS.Berkeley.EDU cxh 24503 0.0 0.0 103320 860 pts/1 S+ 08:47 0:00 grep gdp [cxh@terra gdp]$ Install NodeDownload from http://nodejs.org/ . "Node.js® is a platform built on Chrome's JavaScript runtime [V8] for easily building...." Mac package node 6.0.2 pkg installs into:
and who knows what other locations. Good luck with uninstallation. Node.js docs at http://nodejs.org/api/ Docs on where Node.js looks for loadable modules ( see "requires()" ).
Node package manager, npm, docs at https://www.npmjs.org/doc/ . Note, npm is installed along with Node.js .
Docs on where npm stashes modules that it installs.
Install the node packagesRunning Below is some possibly out of date documentation about what packages are installed by running npm install ffi This creates npm install ref npm install ref-array Create a logIf gdplogd is running, locally, then use: [cxh@terra gdp]$ apps/gcl-create -k none -s `hostname` myLog24 Created new GCL K1GMl3dK9loT9Y5EvMy2r5WmSrc7zjKqdre_mJvn_eg on log server terra.EECS.Berkeley.EDU exiting with status OK See also Create A Remote Log Invoke writer-testcd to the Append a record to the log: [cxh@terra apps]$ echo "foo" | node ./writer-test.js -a myLog24 K1GMl3dK9loT9Y5EvMy2r5WmSrc7zjKqdre_mJvn_eg Starting to read input - ^D to end Got input <<foo>> recno 1, len 0, ts 2016-07-08T15:49:48.432963000Z exiting with status OK [67896520 = 0x40c04c8] Invoke reader-testRead from the log: [cxh@terra apps]$ node ./reader-test.js myLog24 working directory: /home/cxh/src/gdp/lang/js/apps Reading GCL K1GMl3dK9loT9Y5EvMy2r5WmSrc7zjKqdre_mJvn_eg >>> recno 1, len 4, ts 2016-07-08T15:49:48.432963000Z 00000000 66 6f 6f 00 f o o ? exiting with status WARNING: end of file [EPLIB:generic:3] Berkeley GDP ServersBelow are instructions that should work without running local gdplogd and gdp_router processes. Create A Remote LogTo create a log on a remote server, try bash-3.2$ export LOGNAME=edu.berkeley.eecs.$logname.`date +%h.%d.%H.%M.%S` bash-3.2$ $PTII/vendors/gdp/gdp/apps/gcl-create -D*=10 -k none -G gdp-03.eecs.berkeley.edu -s edu.berkeley.eecs.gdp-03.gdplogd $LOGNAME _gdp_chan_open(gdp-03.eecs.berkeley.edu) Trying gdp-03.eecs.berkeley.edu Talking to router at gdp-03.eecs.berkeley.edu:8007 _gdp_advertise => OK gdp_init: OK Couldn't open GCL xAkqr5wFzbkHZzdRITP_O-rLMAIIUX8rAkYIrb2bXJc: ERROR: 600 no route available [Berkeley:Swarm-GDP:600] Creating log as cxh@terramac1.local gdp_gcl_create: OK [67896521 = 0x40c04c9] Created new GCL xAkqr5wFzbkHZzdRITP_O-rLMAIIUX8rAkYIrb2bXJc on log server edu.berkeley.eecs.gdp-03.gdplogd exiting with status OK bash-3.2$ We use export LOGNAME=edu.berkeley.eecs.$logname.`date +d.M.%S` so that a new log is created on the server for the following steps Append a record to the log: ash-3.2$ echo "foo" | node ./writer-test.js -a $LOGNAME writer-test2.js: main()4 writer-test2: argc: 1 writer-test2.main(): about to call write_gcl_records gdpjs.js: write_gcl_records() start gdpjs.js: write_gcl_records() about to call gdp_init_js() gdpjs.js: gdp_init_js(null) gdpjs.js: gdp_init_js(null): calling libgdp.gdp_init(null) gdpjs.js: write_gcl_records() about to call gdp_parse_name_js():edu.berkeley.eecs..Aug.17.17.55.58\ , 40,96,96,212,249,0,0,0,179,134,0,0,255,127,0,0,54,82,165,0,1,0,0,0,11,0,0,0,0,0,0,0 gdpjs.js: write_gcl_records() gcliname: 286060d4f9000b38600ff7f003652a501000b0000000 gdpjs.js: gdp_parse_name_js(): edu.berkeley.eecs..Aug.17.17.55.58, ... gdpjs.js: gdp_parse_name_js(): edu.berkeley.eecs..Aug.17.17.55.58, f6ecfade349ad5d8e5beec3915cf107b6390410ab59404ba1afe4fefc9822b gdpjs.js: write_gcl_records() gcliname: f6ecfade349ad5d8e5beec3915cf107b6390410ab59404ba1afe4fefc9822b gdpjs.js: write_gcl_records() about to call gdp_gcl_open_js() 9uz63jSa1djlvuw5Fc8Qe2OQBBCrWUBLoa_k_g_Jgis Starting to read input - ^D to end warning: this program uses gets(), which is unsafe. Got input <<foo>> gdpjs.js: write_gcl_records() about to call gdp_gcl_publish_buf_js() gdpjs.js: write_gcl_records() done with to call gdp_gcl_publish_buf_js() recno 1, len 0, ts 2016-08-18T00:56:17.295540000Z +/- 0.500000 exiting with status OK [67896520 = 0x40c04c8] bash-3.2$ Read from the log: bash-3.2$ node ./reader-test.js $LOGNAME working directory: /Users/cxh/ptII/vendors/gdp/gdp/lang/js/apps gdpjs.js: read_gcl_records ep_dbg.c: ep_dbg_set(*=40) gdpjs.js: gdp_init_js(null) gdpjs.js: gdp_init_js(null): calling libgdp.gdp_init(null) gdpjs.js: gdp_parse_name_js(): edu.berkeley.eecs..Aug.17.17.55.58, ... gdpjs.js: gdp_parse_name_js(): edu.berkeley.eecs..Aug.17.17.55.58, f6ecfade349ad5d8e5beec3915cf107b6390410ab59404ba1afe4fefc9822b gdpjs.js: read_gcl_records: gclname: 32 f6ecfade349ad5d8e5beec3915cf107b6390410ab59404ba1afe4fefc9822b Reading GCL 9uz63jSa1djlvuw5Fc8Qe2OQBBCrWUBLoa_k_g_Jgis >>> recno 1, len 4, ts 2016-08-18T00:56:17.295540000Z +/- 0.500000 00000000 66 6f 6f 00 f o o ? gdpjs.js: read_gcl_records(): do_simpleread() is not ok WARNING: end of file [EPLIB:generic:3] bash-3.2$ TestingWe use mocha to test Error messages and solutionsConfigurationSee gdp/README.md for how libgdp looks for configuration information. In summary, what happens is that the following path is searched: .ep_adm_params:~/.ep_adm_params:/usr/local/etc/ep_adm_params:/etc/ep_adm_params For example, if swarm.gdp.routers=gdp-01.eecs.berkeley.edu; gdp-02.eecs.berkeley.edu; gdp-03.eecs.berkeley.edu Then each host is queried (in order) to see if it is a gdp router. If it is not, then the next host is checked. This parameter is consulted only if zero-conf fails. Invoke simple_reader_V01.js.txtYou are better off using reader-test.js, simple_reader_v01.js is a bit of a mess. Edit var gclname_arg = "oUDAwe2i3vK4MDY7o2KqTX0lXCYpYFRIIfVW4WZhtv8"; In the [cxh@terra apps]$ node ./simple_reader_01.js simple: before gdp_gcl_open() simple: after gdp_gcl_open() after open, estat: OK simple: about to print the gcl after open simple: about to call gdp_datum_new() simple: after calling gdp_datum_new() simple: About to read record #1 from GCL 'oUDAwe2i3vK4MDY7o2KqTX0lXCYpYFRIIfVW4WZhtv8' after read, estat: OK [67896525 = 0x40c04cd] simple: Done reading record #1 from GCL 'oUDAwe2i3vK4MDY7o2KqTX0lXCYpYFRIIfVW4WZhtv8' read: 'foo' [cxh@terra apps]$ Compare this with reader-testbash-3.2$ apps/reader-test xuNqb5yb3g0RBzDKKYwhyyIoIglfAygxiOjH-N8JGFA Reading GCL xuNqb5yb3g0RBzDKKYwhyyIoIglfAygxiOjH-N8JGFA >>> GDP record 1, len 10, timestamp 2014-10-11T00:53:04.234561000Z «Item_00001» >>> GDP record 2, len 11, timestamp 2014-10-11T00:53:16.750195000Z «Item_000002» >>> GDP record 3, len 12, timestamp 2014-10-11T00:53:22.878067000Z «Item_0000003» >>> GDP record 4, len 13, timestamp 2014-10-11T00:53:29.829537000Z «Item_00000004» ... >>> GDP record 46, len 4, timestamp 2014-10-16T07:17:13.468838000Z «qwer» >>> GDP record 47, len 1, timestamp 2014-10-16T07:18:25.460935000Z «1» >>> GDP record 48, len 30, timestamp 2014-10-16T18:44:23.493667000Z «The most recent Item as of Now» exiting with status WARNING: end of file [EPLIB:generic:3] bash-3.2$ Debug Not WorkingIn libep.ep_dbg_set("*=40"); Analysis showed that in But in The problem was that when To see this, edit Rebuilding the shared library will show: .. ../ep/libep.a(ep_crypto.o) ../ep/libep.a(ep_thr.o) This is because under Mac OS X, The solution is to edit LIBSEARCH= -L${CRYPTOROOT}/lib \ -L${LOCALLIBSDIR} \ -L${LIBROOT}/ep \ -L${LOCAL1}/lib \ -L${LOCAL2}/lib Debug FileAs a small example, we try to set the debug file in C and then in JavaScript Debug File C CodeHere, in bash-3.2$ cat epTest.c #include <stdio.h> #include <ep.h> #include <ep_dbg.h> int main(int argc, char **argv) { FILE *fp = fopen("foo.txt", "w"); ep_dbg_setfile(fp); printf("ep_dbg_getfile(): %p\n", ep_dbg_getfile()); } bash-3.2$ cp ../libs/libgdp.0.7.dylib ../libs/libgdp.so.0.7 bash-3.2$ cc -I ../ep/ -Wl,-rpath,/Users/cxh/ptII/vendors/gdp/gdp/libs -I .. epTest.c -L ../libs -\ lgdp.0.7 bash-3.2$ ./a.out ep_dbg_getfile(): 0x7fff7082b050 bash-3.2$ For details about why we need to do the Debug File JavaScript CodeTo get access to these methods, we have some edits to make:
We get the buffer back? Debug AnalysisIn FILE *DebugFile; The library that is loaded is bash-3.2$ nm $PTII/node_modules/@terraswarm/gdp/libs/libep.3.0.dylib | grep DebugFile 000000000000d210 S _DebugFile The Using bash-3.2$ nm -m $PTII/node_modules/@terraswarm/gdp/libs/libep.3.0.dylib | grep DebugFile 000000000000d210 (__DATA,__common) external _DebugFile Another possibility is that the libgdp shared library has libep statically linked to it, but when we call the Debug SolutionThe libgdp shared library is linked statically to libep.a, so instead of looking for the ep_* symbols in libep, we look in libgdp. If we get the ep_* symbols from the libep shared library, then they will be different than the ep_* symbols that are used by calls in the libgdp shared library, which means that debugging will appear not to work. So, in //var libep = ffi.Library(GDP_DIR + '/libs/libep.3.0', { var libep = ffi.Library(GDP_DIR + '/libs/libgdp.0.7', { Segfaultbash-3.2$ node simple_reader_01.js _gdp_lib_init(NULL) @(#)Gdplib 0.6.1 (2016-06-24_17:25) My GDP routing name = Q5cTD_fQv5cjmLv7J_lgag-pT6NjmzST2DMm7m8Nvh0 gdp_lib_init: OK _gdp_chan_open(127.0.0.1:8007) Trying 127.0.0.1:8007 _gdp_chan_open: trying host 127.0.0.1 port 8007 successful connect Talking to router at 127.0.0.1:8007 _gdp_chan_open => OK _gdp_advertise(1): _gdp_pdu_out, fd = 15, basemd = 0x0: PDU@0x103500510: v=3, ttl=15, rsvd1=0, cmd=1=CMD_ADVERTISE dst=_wD_AP8A_wD_AP8A_wD_AP8A_wD_AP8A_wD_AP8A_wA src=Q5cTD_fQv5cjmLv7J_lgag-pT6NjmzST2DMm7m8Nvh0 rid=0, olen=0, chan=0x0, seqno=0 flags=0 datum=0x103500aa0, recno=(none), dbuf=0x103500b20, dlen=0 ts=(none) sigmdalg=0x0, siglen=0, sig=0x0 total header=80 gdp_event_loop: starting up I/O base loop _gdp_pdu_out: sending PDU: Inserted events: 00000000 03 0f 00 01 ff 00 ff 00 ff 00 ff 00 ff 00 ff 00 00000010 ff 00 ff 00 ff 00 ff 00 ff 00 ff 00 ff 00 ff 00 00000020 ff 00 ff 00 43 97 13 0f f7 d0 bf 97 23 98 bb fb 00000030 27 f9 60 6a 0f a9 4f a3 63 9b 34 93 d8 33 26 ee 00000040 6f 0d be 1d 00 00 00 00 00 00 00 00 00 00 00 00 0x101e07Segmentation fault: 11 bash-3.2$ Under Mac OS X, the (gdb) r simple_reader_01.js Starting program: /usr/local/bin/node simple_reader_01.js [New Thread 0x1313 of process 71324] [New Thread 0x1403 of process 71324] [New Thread 0x1503 of process 71324] [New Thread 0x1603 of process 71324] [New Thread 0x1703 of process 71324] /Users/cxh/ptII/vendors/node_modules/ffi/lib/dynamic_library.js:74 throw new Error('Dynamic Linking Error: ' + err) ^ Error: Dynamic Linking Error: dlopen(../../../libs/libgdp.dylib, 2): Library not loaded: libep.so.3.0 Referenced from: /Users/cxh/ptII/vendors/gdp/gdp/gdp/libgdp.so.0.5 Reason: image not found at new DynamicLibrary (/Users/cxh/ptII/vendors/node_modules/ffi/lib/dynamic_library.js:74:11) at Object.Library (/Users/cxh/ptII/vendors/node_modules/ffi/lib/library.js:45:12) at Object.<anonymous> (/Users/cxh/ptII/vendors/gdp/gdp/lang/js/apps/simple_reader_01.js:70:18) at Module._compile (module.js:541:32) at Object.Module._extensions..js (module.js:550:10) at Module.load (module.js:458:32) at tryModuleLoad (module.js:417:12) at Function.Module._load (module.js:409:3) at Function.Module.runMain (module.js:575:10) at startup (node.js:160:18) [Inferior 1 (process 71324) exited with code 01] (gdb) The problem here is that bash-3.2$ otool -L ../../../libs/libgdp.dylib ../../../libs/libgdp.dylib: libgdp.so.0.5 (compatibility version 0.0.0, current version 0.0.0) libep.so.3.0 (compatibility version 0.0.0, current version 0.0.0) /opt/local/lib/libevent-2.0.5.dylib (compatibility version 7.0.0, current version 7.9.0) /opt/local/lib/libevent_pthreads-2.0.5.dylib (compatibility version 7.0.0, current version 7.9.0) /opt/local/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0) /opt/local/lib/libavahi-client.3.dylib (compatibility version 6.0.0, current version 6.9.0) /opt/local/lib/libavahi-common.3.dylib (compatibility version 9.0.0, current version 9.3.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1) We used to be able to use DYLD_LIBRARY_PATH, but that does not seem to help: bash-3.2$ echo $DYLD_LIBRARY_PATH /Users/cxh/ptII/vendors/gdp/gdp/libs bash-3.2$ ls /Users/cxh/ptII/vendors/gdp/gdp/libs/libep.so.3.0 /Users/cxh/ptII/vendors/gdp/gdp/libs/libep.so.3.0 The solution is to use the Mac OS X bash-3.2$ install_name_tool -change libep.so.3.0 /Users/cxh/ptII/vendors/gdp/gdp/libs/libep.dylib /Users/cxh/ptII/vendors/gdp/gdp/libs/libgdp.dylib bash-3.2$ otool -L ../../../libs/libgdp.dylib ../../../libs/libgdp.dylib: libgdp.so.0.5 (compatibility version 0.0.0, current version 0.0.0) /Users/cxh/ptII/vendors/gdp/gdp/libs/libep.dylib (compatibility version 0.0.0, current version 0.0.0) /opt/local/lib/libevent-2.0.5.dylib (compatibility version 7.0.0, current version 7.9.0) /opt/local/lib/libevent_pthreads-2.0.5.dylib (compatibility version 7.0.0, current version 7.9.0) /opt/local/lib/libcrypto.1.0.0.dylib (compatibility version 1.0.0, current version 1.0.0) /opt/local/lib/libavahi-client.3.dylib (compatibility version 6.0.0, current version 6.9.0) /opt/local/lib/libavahi-common.3.dylib (compatibility version 9.0.0, current version 9.3.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1) after The following change to libgdp.so.${GDPLIBVER}: ${OBJS} ${CC} ${SHARED} -o $@ ${OBJS} ${LDFLAGS} if [ `uname` = 'Darwin' ]; then \ echo "Mac OS X: Running install_name_tool to add full path to libep"; \ install_name_tool -change libep.so.3.0 `(cd ../ep; pwd)`/libep.so.3.0 $@; \ echo "otool -L should list the full path to libep:"; \ otool -L $@; \ fi GDB Stacktrace has no line numbersUnder Mac OS X, in (gdb) r simple_reader_01.js ... Program received signal SIGSEGV, Segmentation fault. 0x000000010326974e in ?? () from /Users/cxh/ptII/vendors/gdp/gdp/gdp/libgdp.so.0.5 (gdb) where #0 0x000000010326974e in ?? () from /Users/cxh/ptII/vendors/gdp/gdp/gdp/libgdp.so.0.5 #1 0x0000000101d115e0 in ?? () #2 0x2400faa00a91dcb3 in ?? () The workaround is to update This gets a bit more information: (gdb) where #0 0x00007fff92d20f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib #1 0x00007fff954664ec in pthread_kill () from /usr/lib/system/libsystem_pthread.dylib #2 0x00007fff9130a6e7 in abort () from /usr/lib/system/libsystem_c.dylib #3 0x0000000101fc6486 in ep_assert_failure (type=<optimized out>, file=<optimized out>, line=<optimized out>, msg=<optimized out>) at ep_assert.c:88 #4 0x0000000101fe2846 in ?? () from /Users/cxh/ptII/vendors/gdp/gdp/gdp/libgdp.so.0.5 #5 0x0000000103306120 in ?? () #6 0x5a00ab25730a5533 in ?? () #7 0x0000000000000000 in ?? () These changes:
GDP_ASSERT_GOOD_GCL assertionIn EP_STAT _gdp_gcl_read(gdp_gcl_t *gcl, gdp_datum_t *datum, gdp_chan_t *chan, uint32_t reqflags) { EP_STAT estat = GDP_STAT_BAD_IOMODE; gdp_req_t *req; errno = 0; // avoid spurious messages ----> GDP_ASSERT_GOOD_GCL(gcl); EP_ASSERT_POINTER_VALID(datum); Summary about how to reproduce
EP_STAT _gdp_gcl_read(gdp_gcl_t *gcl, gdp_datum_t *datum, gdp_chan_t *chan, uint32_t reqflags) { EP_STAT estat = GDP_STAT_BAD_IOMODE; gdp_req_t *req; errno = 0; // avoid spurious messages ----> GDP_ASSERT_GOOD_GCL(gcl); EP_ASSERT_POINTER_VALID(datum); SolutionIt turns out that the problem was that the declaration for The symptoms were that if, in gdp/gdp_api.c, gdp_gcl_open() was modified to print the pointer that was being assigned: if (EP_STAT_ISOK(estat)) { fprintf(stderr, "%s gdp_gcl_open(): EP_STAT_ISOK(): Setting *pgcl (%p) to %\ p!\n", __FILE__, pgcl, gcl); *pgcl = gcl; } Then in simple_reader_01.js, calling estat = libgdp.gdp_gcl_open(gclname, GDP_MODE_RO, ref.NULL, gclPtrPtr); ... gcl_Ptr = gclPtrPtr.deref(); console.log("simple: gcl_Ptr:" + gcl_Ptr + " " + gcl_Ptr.address().toString(16)); console.log(gcl_Ptr); The solution was to declare the third argument as a void *, not a void: var voidPtrType = ref.refType(ref.types.void); ... var libgdp = ffi.Library('../../../libs/libgdp-0.5', { ... 'gdp_gcl_open': ['ulong', [gcl_name_t, gdp_iomode_t, voidPtrType, gdp_gcl_tPtrPtr]], DebuggingDebugging gdpdUse gdpd/gdpd '-D*=30' & Error: "Dynamic Symbol Retrieval Error"bash-3.2$ node gdp.js node gdp.js /Users/cxh/ptII/org/terraswarm/gdp/js/node_modules/ffi/lib/dynamic_library.js:112 throw new Error('Dynamic Symbol Retrieval Error: ' + this.error()) ^ Error: Dynamic Symbol Retrieval Error: dlsym(0x1020036b0, log_view_ls): symbol not found at DynamicLibrary.get (/Users/cxh/ptII/org/terraswarm/gdp/js/node_modules/ffi/lib/dynamic_library.js:112:11) at /Users/cxh/ptII/org/terraswarm/gdp/js/node_modules/ffi/lib/library.js:50:19 at Array.forEach (native) at Object.Library (/Users/cxh/ptII/org/terraswarm/gdp/js/node_modules/ffi/lib/library.js:47:28) at Object.<anonymous> (/Users/cxh/ptII/org/terraswarm/gdp/js/gdp.js:8:18) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12) at Function.Module.runMain (module.js:497:10) The first problem here is that var libgdp = ffi.Library('./libgdp.1.0', { 'gdp_init': [ 'ulong', [ 'string' ] ], 'log_view_ls': [ 'int', [ ] ] }) The problem is with the The second problem is that log_view_ls is not in the current version of gdp. Using find, I see that log_view_ls only appears in the gdp.js files that I'm working on: bash-3.2$ find ~/src/gdp -type f -print0 | xargs -0 grep log_view_ls /Users/cxh/src/gdp/libs/gdp.js: 'log_view_ls': [ 'int', [ ] ] /Users/cxh/src/gdp/libs/gdp.js:console.log( "Calling libgdp.log_view_ls();\n" ); /Users/cxh/src/gdp/libs/gdp.js:var output = libgdp.log_view_ls(); /Users/cxh/src/gdp/libs/gdp.js:console.log( "Result of libgdp.log_view_ls()" + " = " + output + "\n\n" ); /Users/cxh/src/gdp/libs/gdp.js.ok://console.log( "Calling libgdp.log_view_ls();\n" ); /Users/cxh/src/gdp/libs/gdp.js.ok://var output = libgdp.log_view_ls(); /Users/cxh/src/gdp/libs/gdp.js.ok://console.log( "Result of libgdp.log_view_ls()" + " = " + output + "\n\n" ); /Users/cxh/src/gdp/libs/gdp.js~: 'log_view_ls': [ 'int', [ ] ] /Users/cxh/src/gdp/libs/gdp.js~:console.log( "Calling libgdp.log_view_ls();\n" ); /Users/cxh/src/gdp/libs/gdp.js~:var output = libgdp.log_view_ls(); /Users/cxh/src/gdp/libs/gdp.js~:console.log( "Result of libgdp.log_view_ls()" + " = " + output + "\n\n" ); bash-3.2$ The solution is to turn on debugging. Change gdp.js so that we define the ep_dbg_set function and don't define log_view_js var libgdp = ffi.Library('./libgdp.1.0', { 'gdp_init': [ 'ulong', [ 'string' ] ], 'ep_dbg_set': ['void', [ 'string' ] ] // 'log_view_ls': [ 'int', [ ] ] }) // 1) This simple-signature call to a non-"evented" GDP listing function works. // While it doesn't invoke the GDP proper, this does prove, though, that // node-called C programs can read and write files. // //console.log( "Calling libgdp.log_view_ls();\n" ); //var output = libgdp.log_view_ls(); //console.log( "Result of libgdp.log_view_ls()" + " = " + output + "\n\n" ); console.log("Setting debugging.\n"); libgdp.ep_dbg_set("gdp.proto=100"); console.log("Done setting debugging.\n"); Error: running gdp_init("2468") loops endlesslyNow that we have debugging turned on we see that we get a loop: bash-3.2$ node gdp.js Setting debugging. Done setting debugging. Calling libgdp.gdp_init("2468"); ^[[33mgdp_init: initializing ^[[0m^[[33mgdp_init: contacting host 2468 port (null) ^[[0m^[[33mgdp_init: after getaddrinfo(),returned r=0 ^[[0m^[[33mgdp_init: before while a=0x102400430 ^[[0m^[[33mgdp_init: in a=0x102400430, gdpd_port=0 ^[[0m^[[33mgdp_init: in a=0x102400430, gdpd_port=0 ^[[0m^[[33mgdp_init: in a=0x102400430, gdpd_port=0 ^[[0m^[[33mgdp_init: in a=0x102400430, gdpd_port=0 The key line is ^[[0m^[[33mgdp_init: contacting host 2468 port (null)
gdp_proto.c has // get the host:port info into abuf if (gdpd_addr == NULL) gdpd_addr = ep_adm_getstrparam("swarm.gdp.gdpd.addr", NULL); if (gdpd_addr == NULL) snprintf(abuf, sizeof abuf, "127.0.0.1:%d", GDP_PORT_DEFAULT); else strlcpy(abuf, gdpd_addr, sizeof abuf); BTW - curly brackets would really help the readability and maintainability of this code. So, try console.log( "Calling libgdp.gdp_init();\n" ); var output = libgdp.gdp_init("127.0.0.1:2468"); Results: bash-3.2$ node gdp.js Setting debugging. Done setting debugging. Calling libgdp.gdp_init(); ^[[33mgdp_init: initializing ^[[0m^[[33mgdp_init: contacting host 127.0.0.1 port 2468 ^[[0m^[[33mgdp_init: after getaddrinfo(),returned r=0 ^[[0m^[[33mgdp_init: before while a=0x1022004e0 ^[[0m^[[33mgdp_init: in a=0x1022004e0, gdpd_port=41993 ^[[0m^[[33mgdp_init: talking on port 2468, fd 19 ^[[0m^[[33mgdp_init: success ^[[0m^[[33mgdp_event_loop: starting up I/O base loop ^[[0mInserted events: 0x100e05118 [fd 16] Read Persist 0x100e05640 [fd 19] Read Persist 0x100e056c8 [fd 19] Write Persist ^[[33mgdp_event_cb: fd 19: ^[[0m0x80<BEV_EVENT_CONNECTED>^[[33m ^[[0mResult of gdp_init("") = 0 bash-3.2$ The current gdp.js: // HIDE for now - node can't find "ref" module (must set NODE_PATH correctly)) // var ref = require('ref') // ffi module is available locally in my test directory var ffi = require('ffi') var libgdp = ffi.Library('./libgdp.1.0', { 'gdp_init': [ 'ulong', [ 'string' ] ], 'ep_dbg_set': ['void', [ 'string' ] ] // 'log_view_ls': [ 'int', [ ] ] }) // 1) This simple-signature call to a non-"evented" GDP listing function works. // While it doesn't invoke the GDP proper, this does prove, though, that // node-called C programs can read and write files. // //console.log( "Calling libgdp.log_view_ls();\n" ); //var output = libgdp.log_view_ls(); //console.log( "Result of libgdp.log_view_ls()" + " = " + output + "\n\n" ); console.log("Setting debugging.\n"); libgdp.ep_dbg_set("gdp.proto=100"); console.log("Done setting debugging.\n"); // 2) However, when we try to call gdp_init() we have problems. // Debug output from inside gp_init() shows that the call succeeded getting // in but we hang spinning in gdp/gdp_proto.c: _gdp_do_init_2() // waiting on a call to libevent2's entry bufferevent_socket_connect() // which, evidently, never succeeds. // Note, 2468 is the default gdpd port. // console.log( "Calling libgdp.gdp_init();\n" ); var output = libgdp.gdp_init("127.0.0.1:2468"); // We never get here console.log( "Result of gdp_init(\"\")" + " = " + output + "\n\n" ); 4. writer-test.js can write a GCL itemTo: Christopher (Eric, just FYI) From: Alec 1) I've gotten a JS-ized version of writer-test.c (writer-test.js) to create a new GCL and write one hard-wired item into it (bold below). 2870$ ./reader-test gE40_V0kKFjH4_MyUutVZxSk-lwA2dQ0KHmxDbJX4WE Reading GCL gE40_V0kKFjH4_MyUutVZxSk-lwA2dQ0KHmxDbJX4WE >>> GDP record 1, len 28, timestamp 2014-10-06T03:40:15.141718000Z «Item_01 from writer-test.js» exiting with status WARNING: end of file [EPLIB:generic:3] 2871$ This debugging version of writer-test.js is attached (no apologies for the current very ugly state of the code -- cleanup/doc will come). writer-test.js assumes (I think these are the major assumptions): a) libgdp.1.0.dylib and libep.1.0.dylib (both dynamic) are available in a subdir libs/ : 2926$ lsa writer-test.js libs/ -rw-r--r-- 1 ada staff 11540 Oct 5 20:29 writer-test.js libs/: -rwxr-xr-x 1 ada staff 56668 Oct 5 16:18 libep.1.0.dylib* // a copy of libep.so.2.0 for node-ffi library name convention -rwxr-xr-x 1 ada staff 56668 Oct 5 20:37 libep.so.2.0* -rwxr-xr-x 1 ada staff 102304 Oct 5 20:37 libgdp.1.0.dylib* // ditto for libgdp.so.1.0 -rwxr-xr-x 1 ada staff 102304 Oct 5 20:37 libgdp.1.0.so* -rwxr-xr-x 1 ada staff 102304 Oct 5 20:37 libgdp.so.1.0* b) somewhere up the path from writer-test.js's directory are at least these node modules (loaded with "npm install ffi", "npm install ref", "npm install ref-array". Check with "npm list".): 2927$ lsa ../../../node_modules/ drwxr-xr-x 19 ada staff 646 Sep 22 22:28 ffi/ drwxr-xr-x 15 ada staff 510 Oct 1 02:47 ref/ drwxr-xr-x 12 ada staff 408 Oct 5 10:29 ref-array/ To run: >> node writer-test.js # 20 lines or so of Ugly Debug Output. # To verify, grab new GCL's name from /......./var/tmp/gcl/<<radix-64>>.data and use in: >> apps/reader-test <<radix-64>> 2) Next steps (in parallel?): build up reader-test.js from reader-test.c reader-test.c: do_simpleread() reader-test.c: do_multiread() without subscription reader-test.c: do_multiread() with subscription fill out writer-test.js to full writer-test.c functionality cleanup, (simple) build/deployment process, working docs writer-test.js and reader-test.js work and have a test scriptgdp/lang/js/apps/{ writer-test.js and reader-test.js } are working like gdp/apps/{ writer-test.c and reader-test.c } and gdp/lang/js/(Makefile test) will run a bash testing script in js/tests/. update gdp inside ptII: Pull gdp into ptII/org/terraswarm/gdp/ ptII/org/terraswarm/gdp: 1151$ make update 2>&1 | tee local_ada/06_make_update.out cd src/gdp; git pull Updating 5ea57a3..647b906 Fast-forward lang/js/Makefile | 18 ++ lang/js/README.txt | 44 ++- lang/js/apps/Makefile | 25 +- lang/js/apps/README.txt | 30 +- lang/js/tests/.gitignore | 1 + lang/js/tests/Makefile | 35 +++ lang/js/tests/README.txt | 106 +++++++ lang/js/tests/wr-test_01_Routput_Good.txt | 12 + lang/js/tests/wr-test_01_Winput.txt | 5 + lang/js/tests/wr-test_01_Woutput_Good.txt | 15 + lang/js/tests/wr-test_02_RALLoutput_Good.txt | 20 ++ lang/js/tests/wr-test_02_RSUBoutput_Good.txt | 10 + lang/js/tests/wr-test_02_WAPPoutput_Good.txt | 13 + lang/js/tests/wr-test_02_Winput.txt | 4 + lang/js/tests/writer_reader-test.js_tests.sh | 338 +++++++++++++++++++++ .../writer_reader-test.js_tests.sh_sample.output | 116 +++++++ 16 files changed, 780 insertions(+), 12 deletions(-) create mode 100644 lang/js/tests/.gitignore create mode 100644 lang/js/tests/Makefile create mode 100644 lang/js/tests/README.txt create mode 100644 lang/js/tests/wr-test_01_Routput_Good.txt create mode 100644 lang/js/tests/wr-test_01_Winput.txt create mode 100644 lang/js/tests/wr-test_01_Woutput_Good.txt create mode 100644 lang/js/tests/wr-test_02_RALLoutput_Good.txt create mode 100644 lang/js/tests/wr-test_02_RSUBoutput_Good.txt create mode 100644 lang/js/tests/wr-test_02_WAPPoutput_Good.txt create mode 100644 lang/js/tests/wr-test_02_Winput.txt create mode 100755 lang/js/tests/writer_reader-test.js_tests.sh create mode 100644 lang/js/tests/writer_reader-test.js_tests.sh_sample.output ptII/org/terraswarm/gdp: 1152$ Re-Make ptII/org/terraswarm/gdp/src/gdp : ptII/org/terraswarm/gdp/src/gdp: 1161$ make all 2>&1 | tee local_ada/02_make_all.out rm libs/* (cd ep; make clean all) rm -f libep.a libep.so.2.0 *.o *.core cc -g -Wall -O -I. -I.. -fPIC -c -o ep_adm.o ep_adm.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_app.o ep_app.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_assert.o ep_assert.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_b64.o ep_b64.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_dbg.o ep_dbg.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_dumpfds.o ep_dumpfds.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_fopensmem.o ep_fopensmem.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_fread_unlocked.o ep_fread_unlocked.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_funclist.o ep_funclist.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_hash.o ep_hash.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_hexdump.o ep_hexdump.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_lib.o ep_lib.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_mem.o ep_mem.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_pcvt.o ep_pcvt.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_pprint.o ep_pprint.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_prflags.o ep_prflags.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_rpool.o ep_rpool.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_stat.o ep_stat.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_statcodes.o ep_statcodes.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_string.o ep_string.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_syslog.o ep_syslog.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_thr.o ep_thr.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_time.o ep_time.c cc -g -Wall -O -I. -I.. -fPIC -c -o ep_xlate.o ep_xlate.c cc -g -Wall -O -I. -I.. -fPIC -D_CURRENT_DATE_=\"`date +'%Y-%m-%d_%H:%M'`\" -c ep_version.c ar -r libep.a ep_adm.o ep_app.o ep_assert.o ep_b64.o ep_dbg.o ep_dumpfds.o ep_fopensmem.o ep_fread_unlocked.o ep_funclist.o ep_hash.o ep_hexdump.o ep_lib.o ep_mem.o ep_pcvt.o ep_pprint.o ep_prflags.o ep_rpool.o ep_stat.o ep_statcodes.o ep_string.o ep_syslog.o ep_thr.o ep_time.o ep_xlate.o ep_version.o ar: creating archive libep.a ranlib libep.a cc -shared -o libep.so.2.0 ep_adm.o ep_app.o ep_assert.o ep_b64.o ep_dbg.o ep_dumpfds.o ep_fopensmem.o ep_fread_unlocked.o ep_funclist.o ep_hash.o ep_hexdump.o ep_lib.o ep_mem.o ep_pcvt.o ep_pprint.o ep_prflags.o ep_rpool.o ep_stat.o ep_statcodes.o ep_string.o ep_syslog.o ep_thr.o ep_time.o ep_xlate.o ep_version.o mv libep.so.2.0 ../libs (cd ../libs; rm -f libep.so.2; ln -s libep.so.2.0 libep.so.2) (cd ../libs; rm -f libep.so; ln -s libep.so.2 libep.so) (cd ../libs; rm -f libep.2.0.dylib; ln -s libep.so.2.0 libep.2.0.dylib) (cd gdp; make clean all) rm -f libgdp.a libgdp.so.1.0 *.o *.core cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_api.o gdp_api.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_buf.o gdp_buf.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_event.o gdp_event.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_gcl.o gdp_gcl.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_log.o gdp_log.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_datum.o gdp_datum.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_pkt.o gdp_pkt.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_proto.o gdp_proto.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_req.o gdp_req.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -fPIC -c -o gdp_stat.o gdp_stat.c ar -r libgdp.a gdp_api.o gdp_buf.o gdp_event.o gdp_gcl.o gdp_log.o gdp_datum.o gdp_pkt.o gdp_proto.o gdp_req.o gdp_stat.o ar: creating archive libgdp.a ranlib libgdp.a cc -shared -o libgdp.so.1.0 gdp_api.o gdp_buf.o gdp_event.o gdp_gcl.o gdp_log.o gdp_datum.o gdp_pkt.o gdp_proto.o gdp_req.o gdp_stat.o -L../ep -lep -levent -levent_pthreads -lcrypto mv libgdp.so.1.0 ../libs (cd ../libs; rm -f libgdp.so.1; ln -s libgdp.so.1.0 libgdp.so.1) (cd ../libs; rm -f libgdp.so; ln -s libgdp.so.1 libgdp.so) (cd ../libs; rm -f libgdp.1.0.dylib; ln -s libgdp.so.1.0 libgdp.1.0.dylib) (cd scgilib; make clean all) rm -f helloworld *.o cc -g -Wall -O -c -o helloworld.o helloworld.c cc -g -Wall -O -c -o scgilib.o scgilib.c cc -o helloworld helloworld.o scgilib.o (cd gdpd; make clean all) rm -f gdpd *.o *.core cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -c -o gdpd.o gdpd.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -c -o gdpd_gcl.o gdpd_gcl.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -c -o gdpd_physlog.o gdpd_physlog.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -c -o gdpd_proto.o gdpd_proto.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -c -o gdpd_pubsub.o gdpd_pubsub.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -c -o gdp_circular_buffer.o gdp_circular_buffer.c cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -c -o thread_pool.o thread_pool.c cc -o gdpd gdpd.o gdpd_gcl.o gdpd_physlog.o gdpd_proto.o gdpd_pubsub.o gdp_circular_buffer.o thread_pool.o -L../ep -L../gdp -lgdp -lep -levent -levent_pthreads -pthread -lcrypto clang: warning: argument unused during compilation: '-pthread' (cd apps; make clean all) rm -f writer-test reader-test gdp-rest rw-bench log-view *.o *.core cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -I/usr/local/include -I/opt/local/include -c -o writer-test.o writer-test.c cc -o writer-test writer-test.o -L../ep -L../gdp -lgdp -lep -L/usr/local/lib -L/opt/local/lib -ljansson -levent -levent_pthreads -pthread -lcrypto clang: warning: argument unused during compilation: '-pthread' cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -I/usr/local/include -I/opt/local/include -c -o reader-test.o reader-test.c cc -o reader-test reader-test.o -L../ep -L../gdp -lgdp -lep -L/usr/local/lib -L/opt/local/lib -ljansson -levent -levent_pthreads -pthread -lcrypto clang: warning: argument unused during compilation: '-pthread' cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -I/usr/local/include -I/opt/local/include -c -o gdp-rest.o gdp-rest.c cc -o gdp-rest gdp-rest.o -L../ep -L../gdp -lgdp -lep -L/usr/local/lib -L/opt/local/lib -ljansson -levent -levent_pthreads -pthread -lcrypto ../scgilib/scgilib.o clang: warning: argument unused during compilation: '-pthread' cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -I/usr/local/include -I/opt/local/include -c -o rw-bench.o rw-bench.c cc -o rw-bench rw-bench.o -L../ep -L../gdp -lgdp -lep -L/usr/local/lib -L/opt/local/lib -ljansson -levent -levent_pthreads -pthread -lcrypto clang: warning: argument unused during compilation: '-pthread' cc -g -Wall -O -I.. -I/usr/local/include -I/opt/local/include -I/usr/local/include -I/opt/local/include -c -o log-view.o log-view.c cc -o log-view log-view.o -L../ep -L../gdp -lgdp -lep -L/usr/local/lib -L/opt/local/lib -ljansson -levent -levent_pthreads -pthread -lcrypto clang: warning: argument unused during compilation: '-pthread' ptII/org/terraswarm/gdp/src/gdp: 1162$ Make gdp/lang/js/ -- makes C support library, gdpjs/libgdpjs.1.0.dylib, for JS support routines, gdpjs/gdpjs_supt.js . Note, gdp/lang/js/Makefile is not yet driven by gdp/Makefile. ptII/org/terraswarm/gdp/src/gdp: 1162$ cd lang/js/ ptII/org/terraswarm/gdp/src/gdp/lang/js: 1168$ make all 2>&1 | tee local_ada/02_make_all.out rm libs/* (cd gdpjs; make clean all) rm -f libgdpjs.a libgdpjs.so.1.0 *.o *.core cc -g -Wall -O -I. -I.. -I../.. -I../../.. -fPIC -c -o gdpjs_supt.o gdpjs_supt.c ar -r libgdpjs.a gdpjs_supt.o ar: creating archive libgdpjs.a ranlib libgdpjs.a cc -shared -o libgdpjs.so.1.0 gdpjs_supt.o -L../../../gdp -lgdp -L../../../ep -lep -levent -levent_pthreads -lcrypto mv libgdpjs.so.1.0 ../libs (cd ../libs; rm -f libgdpjs.so.1; ln -s libgdpjs.so.1.0 libgdpjs.so.1) (cd ../libs; rm -f libgdpjs.so; ln -s libgdpjs.so.1 libgdpjs.so) (cd ../libs; rm -f libgdpjs.1.0.dylib; ln -s libgdpjs.so.1.0 libgdpjs.1.0.dylib) (cd apps; make clean all) # Currently empty - nothing to clean Nothing to make here - only JavaScript programs. See the README here as well as the js/tests/ README. for details on how to run the JS programs here. (cd tests; make clean all) rm *output.tmp rm: *output.tmp: No such file or directory make[1]: [clean] Error 1 (ignored) Nothing to make here - only a bash test script and some manually constructed text files. Consider "make run" to execute the tests. ptII/org/terraswarm/gdp/src/gdp/lang/js: 1169$ Finally, run the test script from lang/js/ using the "make test" target in the js/Makefile. Results of test script go to stdout. Note, there's a false positive hit shown by the diff: ">>>>>>>> Checking reader-test.js -s output" when we're running a reader "-s" process that's subscribed to a test gcl that is concurrently being appended to by a writer "-a" process. The diff seems to arise because of differing order of test output depending on whether the destination is a Terminal or a file (like we are doing in this scripted test situation. We captured the corresponding known good output file manually using a Terminal invoked reader -s. This seems to still happen though the JS code for both reader and writer is explicitly calling fflush() after writes. This issue is noted in the README and in the test script. It's a testing artifact (the subscribe and the appends do work) that I've got on my TBD list. ptII/org/terraswarm/gdp/src/gdp/lang/js/tests: 1171$ cd - /Users/ada/Projects/Work/TerraSwarm/SwarmOSWS/ptII/org/terraswarm/gdp/src/gdp/lang/js ptII/org/terraswarm/gdp/src/gdp/lang/js: 1172$ make test 2>&1 | tee local_ada/02_make_test.out (cd tests; make clean all run) rm *output.tmp rm: *output.tmp: No such file or directory make[1]: [clean] Error 1 (ignored) Nothing to make here - only a bash test script and some manually constructed text files. Consider "make run" to execute the tests. Run the tests of writer-test.js and reader-test.js The reader-test.js -s test is problematic because of, evidently, text output differences between output to a file versus output a terminal from a Node.js JS program; yes, TBD. See the README and the below script for details. ./writer_reader-test.js_tests.sh ======================= HERE's THE ACTUAL TEST OUTPUT =========================== Look for >>>>>>>> Checking for diffs with Known Good files. Tests of writer-test.js and reader-test.js {Sun Nov 9 01:02:51 PST 2014 # These tests exercise the above JS GDP test programs. The tests here # are NOT completely automatic giving, say, a Passed/Not Passed disposition. # # User interaction is required to interpret the results by manually # checking the consistency of the output of programs run during this test # with pre-recorded known good output files. See the result of diffs below. # # Here's a reminder of writer-test.js and reader-test.js command line interface # # Usage: # node ./writer-test.js [-a] [-D dbgspec] [-G gdpd_addr] <gcl_name> # # Usage: # node ./reader-test.js [-D dbgspec] [-f firstrec] [-G gdpd_addr] [-m] [-n nrecs] [-s] <gcl_name> We assume that we are running in gdp/lang/js/test/ pwd = /Users/ada/Projects/Work/TerraSwarm/SwarmOSWS/ptII/org/terraswarm/gdp/src/gdp/lang/js/tests We assume the local GCL directory is in the directory: /var/tmp/gcl/ ls -ld /var/tmp/gcl/ drwxr-xr-x 9 ada wheel 306 Nov 8 23:58 /var/tmp/gcl/ We assume a GDP daemon (gdpd) is NOT currently running. This program will generate gdp-related error output if one is running. First, we start a GDP daemon in the background gdpd.PID = 6371 {======================================================================= Test 1: writer-test.js creates a new gcl; reader-test.js reads it back Running: node ../apps/writer-test.js test_gcl_01 Running: node ../apps/reader-test.js test_gcl_01 Now compare output from the runs above with known good versions. These two diffs might show differences because of odd file output versus terminal output buffering differences of these Node.js JS programs. If unexpected differences do appear, verify the programs manually inside of separate Terminal windows. See comments within this script for more details. >>>>>>>> Checking writer-test.js output diff wr-test_01_Woutput.tmp wr-test_01_Woutput_Good.txt >>>>>>>> Checking reader-test.js output diff wr-test_01_Routput.tmp wr-test_01_Routput_Good.txt Test 1: Done =======================================================================} {======================================================================= Test 2: reader-test.js subscribes to an existing gcl writer-test.js appends to that existing gcl Running: node ../apps/reader-test.js -s test_gcl_01 in background readerSubscribe.PID = 6392 Running: node ../apps/writer-test.js -a test_gcl_01 Check to see if all the appends have been made to the gcl. Read the newly appended gcl starting with the first record (-f 1) Running: node ../apps/reader-test.js -f 1 test_gcl_01 We now kill the reader subscribe process, PID=6392 Now compare output from the runs above with known good versions. These two diffs might show differences because of buffering oddities. See the comments above in Test 1 and within this script. >>>>>>>> Checking writer-test.js -a output diff wr-test_02_WAPPoutput.tmp wr-test_02_WAPPoutput_Good.txt >>>>>>>> Checking reader-test.js -s output This diff, in particular is likely to show buffering-related differences. diff wr-test_02_RSUBoutput.tmp wr-test_02_RSUBoutput_Good.txt 2c2 < >>> >>> GDP record 6, len 24, timestamp-removed --- > >>> GDP record 6, len 24, timestamp-removed 7a8,10 > >>> GDP record 9, len 24, timestamp-removed > «appended line 0004 of 4» > Now compare output from the reading the fully appended gcl with a known good version. >>>>>>>> Checking reader-test.js output reading the newly appended gcl diff wr-test_02_RALLoutput.tmp wr-test_02_RALLoutput_Good.txt Test 2: Done =======================================================================} We now kill the GDP daemon, PID=6371 Sun Nov 9 01:02:58 PST 2014 ./writer_reader-test.js_tests.sh: line 334: 6371 Terminated: 15 ../../../gdpd/gdpd } ~/Projects/Work/TerraSwarm/SwarmOSWS/ptII/org/terraswarm/gdp/src/gdp/lang/js: 1173$ Node.js JavaScript Testing FrameworksFound some possible Node-compatible (server-side -- non-browser-based) test frameworks for JS. Will be looking for the best developed / widely used one. Review of Mocha & Jasmine -- Mocha newer but most Pros Mocha-Related Information: Looks like Mocha is a place to start for Node.js JavaScript testing frameworks. SubscriptionAs of 8/17/16, Subscription using Cape Code works, see $PTII/ptolemy/actor/lib/jjs/modules/gdp/test/auto/GDPLogSubscribe.xml However, Subscription using the Node Accessor host does not work. Subscription OverviewCape Code's GDPHelper.subscribe() spawns a thread to do the dirty work. It looks like the C version of the gdp subscriber in $PTII/vendors/gdp/gdp/apps/gdp-reader.c does something similar. In the Node host, we should be using callbacks. Whether or not we have register a callback function, we are not receiving events. Run the Node Accessor Host Subscription Composite Accessorcd $PTII mkdir node_modules npm install @terraswarm/gdp Run without SubscriptionTo test that the code other than GDPLogSubscribe works, we run a Node Composite Accessor that does not subscribe:
The end of the output should look like: b1ab94b9f7f5c318622dcdff1d91a7834277dc457655502e5a90152d46d2622 Reading GCL sauUuff1wxhiLc3_HZGng0J33EV2VVAuWpAVLUbSBiI >>> recno 5, len 2, ts 2016-08-18T01:54:27.161803000Z +/- 0.500000 00000000 35 00 5 ? exiting with status OK [67896525 = 0x40c04cd] GDPLogRead.read(5): sending 5^@ nodeHostInvoke.js: Timeout of 6000 ms. has occurred. About to invoke wrapup(). The Ptolemy model for the above Composite Accessor is at Run With SubscriptionNext, run the Node Composite Accessor that does subscription:
The model hangs, below is an analysis of the end of the run output. GDPLogSubscribe.js: getNextData() The above is good, it means that getNextData() was called. gdpjs/index.js: gdp_gcl_open(ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.0.9315235907070551, 1, edu.berkeley.eecs.gdp-01.gdplogd) gdpjs/index.js: gdp_gcl_open(ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.0.9315235907070551, 1): calling gdpGclOpen() gdpjs.js: 0 gdpGclOpen(ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.0.9315235907070551, 1, edu.berkeley.eecs.gdp-01.gdplogd): setting debugging (dbg_set_js) gdpjs.js: gdp_parse_name_js(): ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.0.9315235907070551, ... gdpjs.js: gdp_parse_name_js(): ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.0.9315235907070551, 294c6b6f58f22855f121f3b4bc9c5f815034faa71e5b6c8a5a4b4be6a3029 gdpjs.js: 10 gdpGclOpen gcliname: 32 294c6b6f58f22855f121f3b4bc9c5f815034faa71e5b6c8a5a4b4be6a3029 gdpjs.js: gdpGclOpen(): calling gdp_gcl_open_js(), which may fail, but if it does, we will create the log. gdpjs.js: gdpGclOpen(): gdp_gcl_open_js() returned. In the above, the call to gdp.js: setDebugLevel(undefined) In the above, debugging is not being enabled. There is a bug with setting debugging in the GDP/JS interface, see above. node_modules/gdp/gdp.js:subscribe(0, 0, 0) In the above, we have entered the node_modules/gdp/gdp.js:subscribe(): about to call read_gcl_records() In console.log("node_modules/gdp/gdp.js:subscribe(): about to call read_gcl_records()"); var data = gdpjs.read_gcl_records(gdpd_addr, gcl_name, gcl_firstrec, gcl_numrecs, gcl_subscribe, gcl_multiread, /*recdest,*/ conout, gdp_event_cbfunc, wait_for_events ); console.log("node_modules/gdp/gdp.js:subscribe(): returned from read_gcl_records()"); Continuing with the output: gdpjs.js: read_gcl_records gdpjs.js: gdp_init_js(undefined) gdpjs.js: gdp_init_js(undefined): calling libgdp.gdp_init(undefined) gdpjs.js: gdp_parse_name_js(): ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.0.822\ 619457094069, ... gdpjs.js: gdp_parse_name_js(): ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.0.822\ 619457094069, e2ed02aa2d15bf98efff43faabe166f4977d36c0b6147a4acec8bf3dc2c060 gdpjs.js: read_gcl_records: gclname: 32 e2ed02aa2d15bf98efff43faabe166f4977d36c0b6147a4acec8bf3dc2c060 Reading GCL 4u0AKqINFb-Y7_9D-qvhZvSXfTbAthR6Ss7Ivz3CwGA In the above, read_gcl_records() is checking for the handle, which is fine gdpjs.js: read_gcl_records(): before do_multiread() gdpjs.js: do_multiread(ZTUM^@^@^@^@, 0, 0, subscribe: true, wait_for_events: false, recarray_out: , conout: true, null) gdpjs.js: gdp_gcl_subscribe_no_timeout_no_callback_js(ZTUM^@^@^@^@, 0, 0) gdpjs.js: gdp_gcl_subscribe_no_timeout_no_callback_js(): done: 67896520 gdpjs.js: do_multiread() after call to gdp_gcl_multiread_no_callback_js() gdpjs.js: do_multiread(): about to loop gdpjs.js: setting timeout for 5 seconds. gdpjs.js: gdp_event_next_js(ZTUM^@^@^@^@, ^E^@^@^@^@^@^@^@^@^@^@^@^@^@^@) In the above, we call gdp_event_next_js() with a 5 second timeout. The output stops for 5 seconds. Here, I would expect that we would get an event from the append, but we are probably not in a separate thread. In any case, we don't want to be in a separate thread here, we want to use callbacks. gdpjs.js: do_multiread() after call to gdp_event_next_js(). gev_Ptr = <Buffer@0x0 > gdpjs.js: do_multiread() no event found, return with no side-effects on recarray_out or a call of gdp_event_cbfunc. We did not get an event, so we are not updating recarray_out. exiting with status OK [67896520 = 0x40c04c8] I'm not sure about the above. gdpjs.js: read_gcl_records(): done node_modules/gdp/gdp.js:subscribe(): returned from read_gcl_records() We returned from read_gcl_records() GDPLogSubscribe.getNextData(): Call to log.subscribe() ended, about to loop node_modules/gdp/gdp.js: getNextData() is not implemented BTW - gdp.js contains this: exports.GDP.prototype.getNextData = function (timeout) { console.log("node_modules/gdp/gdp.js: getNextData() is not implemented"); }; In our hack of calling read_gcl_records() and returning the data, perhaps getNextData could retrieve the next data? However, what we really want is to use callbacks. Continuing with the output: GDPLogSubscribe.getNextData() data: undefined typeof inputValue object typeof referenceToken string Error: The input "null" is !== to the expected value "datum was null?" at Accessor.exports.fire (eval at Accessor (/Users/cxh/src/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_COMMON}/commonHost.js:444:19), <anonymous>:117:23) at Accessor.react (/Users/cxh/src/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_COMMON}/commonHost.js:1404:27) at Accessor.react (/Users/cxh/src/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_COMMON}/commonHost.js:1398:24) at Timeout._onTimeout (/Users/cxh/src/ptII/org/terraswarm/accessor/accessors/web/{$HOSTS_COMMON}/commonHost.js:1492:38) at tryOnTimeout (timers.js:228:11) at Timer.listOnTimeout (timers.js:202:5) About to invoke wrapup(). In the above, the Test accessor fails because the input is "null" instead of "datum was null" Subscription FilesA review of files is in order:
Subscription AnalysisSee GDP JavaScript Callbacks -> Subscription Analysis?. Subscription CallbacksSee GDP JavaScript Callbacks -> Subscription Callbacks?. Calling the C-based subscribe() functionIt could be that we need to call the C-based subscribe() function.
// From gdp/gdp.h // subscribe to a readable GCL //CJS extern EP_STAT gdp_gcl_subscribe( //CJS gdp_gcl_t *gclh, // readable GCL handle //CJS gdp_recno_t start, // first record to retrieve //CJS int32_t numrecs, // number of records to retrieve //CJS EP_TIME_SPEC *timeout, // timeout //CJS // callback function for next datum //CJS gdp_gcl_sub_cbfunc_t cbfunc, //CJS // argument passed to callback //CJS void *cbarg); // Note, in our call to this function in do_multiread() below we do not // use the last three (pointer) arguments. 'gdp_gcl_subscribe': [EP_STAT, [gdp_gcl_tPtr, gdp_recno_t, int32_t, 'pointer', 'pointer', 'pointer' ]], // From gdp/gdp.h //CJS // read multiple records (no subscriptions) //CJS extern EP_STAT gdp_gcl_multiread( //CJS gdp_gcl_t *gclh, // readable GCL handle //CJS gdp_recno_t start, // first record to retrieve //CJS int32_t numrecs, // number of records to retrieve //CJS // callback function for next datum //CJS gdp_gcl_sub_cbfunc_t cbfunc, //CJS // argument passed to callback //CJS void *cbarg); // Note, in our call to this function in do_multiread() below we do not // use the last two (pointer) arguments. 'gdp_gcl_multiread': [EP_STAT, [gdp_gcl_tPtr, gdp_recno_t, int32_t, 'pointer', 'pointer' ]], There are two functions defined in // TBD: WARNING - likely will JS blow up at FFI LEFT OFF HERE /* EP_STAT */ function gdp_gcl_subscribe_no_callback_js(gclh, firstrec, numrecs, timeout /* seconds */ ) // This is a limited-functionality version of // libgdp.gdp_gcl_subscribe(gclh, firstrec, numrecs, timeout, cbfunc, cbarg); // See the comments on callbacks below for: // gdp_gcl_subscribe_no_timeout_no_callback_js() . // A smaller issue is passing in the EP_TIME_SPEC timeout argument (a C struct). // Node.js ref-struct should provide a straight-forward FFI implementation. // This smaller issue is also TBD. { var rv_estat; if (debug) { console.log("gdpjs.js: gdp_gcl_subscribe_no_callback_js(" + gclh + ", " + firstrec + ", " \ + numrecs + ", "+ _timeout + ")"); } // EP_TIME_SPEC *timeout, gdp_gcl_sub_cbfunc_t cbfunc, void *cbarg // are all null here for a simpler subscribe variant. See gdp/gdp-api.[ch] // gdp_gcl_subscribe() for details. // TBD: this use of timeout should blow up at the FFI - time to bite the // bullet and use ref-struct ? rv_estat = libgdp.gdp_gcl_subscribe(gclh, firstrec, numrecs, timeout, null, null); if (debug) { console.log("gdpjs.js: gdp_gcl_subscribe_no_callback_js() done: " + rv_estat); } return rv_estat; }; /* EP_STAT */ function gdp_gcl_subscribe_no_timeout_no_callback_js(gclh, firstrec, numrecs) // This is a limited-functionality version of // libgdp.gdp_gcl_subscribe(gclh, firstrec, numrecs, timeout, cbfunc, cbarg); // We currently do not have a mechanism for invoking a JS callback function // from down in the C level. We are looking for a solution here using the // Node.js FFI mechanism. TBD // A smaller issue is passing in the EP_TIME_SPEC timeout argument (a C struct). // Node.js ref-struct should provide a straight-forward FFI implementation. // This smaller issue is also TBD. { var rv_estat; if (debug) { console.log("gdpjs.js: gdp_gcl_subscribe_no_timeout_no_callback_js(" + gclh + ", " + first\ rec + ", " + numrecs + ")"); } // EP_TIME_SPEC *timeout, gdp_gcl_sub_cbfunc_t cbfunc, void *cbarg // are all null here for a simpler subscribe variant. See gdp/gdp-api.[ch] // gdp_gcl_subscribe() for details. rv_estat = libgdp.gdp_gcl_subscribe(gclh, firstrec, numrecs, null, null, null); if (debug) { console.log("gdpjs.js: gdp_gcl_subscribe_no_timeout_no_callback_js(): done: " + rv_estat); } return rv_estat; }; /* EP_STAT */ function gdp_gcl_multiread_no_callback_js(gclh, firstrec, numrecs) // This is a limited-functionality version of // libgdp.gdp_gcl_multiread(gclh, firstrec, numrecs, cbfunc, cbarg); // See the comments on callbacks above for: // gdp_gcl_subscribe_no_timeout_no_callback_js() . { var rv_estat; // gdp_gcl_sub_cbfunc_t cbfunc, void *cbarg are both null here for a // simpler multiread variant. See gdp/gdp-api.[ch] gdp_gcl_multiread() . rv_estat = libgdp.gdp_gcl_multiread(gclh, firstrec, numrecs, null, null); return rv_estat; }
if (subscribe) { //C // start up a subscription estat = gdp_gcl_subscribe_no_timeout_no_callback_js( gclh, firstrec, numrecs); Subscription as a separate processInterestingly, running a Node Host Composite Accessor that appends to a log in one process and a Node Host Composite Accessor that subscribes to a log works somewhat.
Problems:
Getting the Next DataThe issue here is that GDPLogSubscribe.js calls log.subscribe(this, this.getParameter('startrec'), this.getParameter('numrec'), this.getParameter('timeout')); console.log("GDPLogSubscribe.getNextData(): Call to log.subscribe() ended, about to loop"); // This blocks. while (true) { var data = log.getNextData(100); console.log("GDPLogSubscribe.getNextData() data: " + data); if (data !== null) { this.send('data', data); break; } } The problem is that |