Recent Changes - Search:

edit SideBar

GDPJSNotes

This page contains old and obsolete notes about the GDP JavaScript Interface.

See GDP JS for more recent information.

Overview

This 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 gdp/lang/js

  • gdp/lang/js/apps
    • reader-test.js A partial port of the C-based reader-test example
    • simple_reader_01.js A simple reader that does not use the gdpjs code. See Invoke simple_reader_V01.js.txt
    • writer-test.js A partial port of the C-based writer-test example
  • gdp/lang/js/gdpjs/ C code that provides an easier to interface-to set of functions for C code that is cpp macros
  • gdp/lang/js/libs/ The libgdpjs shared library used by reader-test.js and writer-test.js
  • gdp/lang/js/test/ Node mocha tests, see Testing
  • gdp/lang/js/tests/ Older script-based tests.

See Also

Notes about getting it to work

Get access to the gdp repo

Ask Eric Allman for access to the gdp repo.

Build the gdp

git clone https://repo.eecs.berkeley.edu/git/projects/swarmlab/gdp.git
cd gdp
make

If make does not work, then read the gdp README file. In particular, on the Mac, you may need install Mac Ports and do

sudo -i port install libevent
sudo -i port install jansson

Start up gdp_router and gdplogd

To run the gdp_router.py and gdplogd on your local machine, while in the gdp/ directory, invoke test/setupAndRun.sh, let it run and then put it in the background. FIXME: The issue here is that the script may prompt the user for their git credentials to update the router directory.

[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 Node

Download 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:

  • /usr/local/bin/node // Node.js executable
  • /usr/local/bin/npm // Node package manager executable (implemented as a JS script - "#!/usr/bin/env node")
  • /usr/local/include/node/ // Also contains vc8.h which might be useful
  • /usr/local/lib/node_modules/ // Location for npm's "global" modules
  • /usr/local/share/man/man1/node.1 // Meager man page

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 packages

Running (cd gdp/lang/js/; make) does the npm installs for you.

Below is some possibly out of date documentation about what packages are installed by running make.

npm install ffi

This creates node_modules in the current directory (which should be gdp/ as the JavaScript below expects to find libraries in libs/)

npm install ref
npm install ref-array

Create a log

If 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-test

cd to the gdp/lang/js/apps directory

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-test

Read 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 Servers

Below are instructions that should work without running local gdplogd and gdp_router processes.

Create A Remote Log

To 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$

Testing

We use mocha to test

Error messages and solutions

Configuration

See 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 .ep_adm_params/gdp is found, then the values of that file are used to configure the gdp. If that file contains

  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.txt

You are better off using reader-test.js, simple_reader_v01.js is a bit of a mess.

Edit gdp/lang/js/apps/simple_reader_v01.js and update var gclname_arg to match the output of gcl-create above:

var gclname_arg = "oUDAwe2i3vK4MDY7o2KqTX0lXCYpYFRIIfVW4WZhtv8";

In the gdp/lang/js/apps/ directory, invoke

[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-test

bash-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 Working

In simple_reader_01.js, debugging was being set with:

libep.ep_dbg_set("*=40");
However, the debug messages were not appearing.

Analysis showed that in gdp/ep/ep_dbg.c, FlagList was being set in ep_dbg_setto()

But in ep_dbg_flaglevel(), FlagList was 0!

The problem was that when libgdp was being created, we were linking with the static libep.a library.

To see this, edit gdp/gdp/Makefile and add -Wl,-t to the line that creates the shared library.

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, ../ep contains libep.a and libep.so.3.0. However the linker is looking for libep.dylib, does not find it and uses libep.a instead. Probably in static libraries, the visibility of the static FlagList is somehow different.

The solution is to edit gdp/gdp/Makefile and add -L${LOCALLIBSDIR} \ so that .dylib files in gdp/gdp/libs are found and used.

LIBSEARCH=      -L${CRYPTOROOT}/lib \
                -L${LOCALLIBSDIR} \
                -L${LIBROOT}/ep \
                -L${LOCAL1}/lib \
                -L${LOCAL2}/lib

Debug File

As a small example, we try to set the debug file in C and then in JavaScript

Debug File C Code

Here, in epTest.c calls ep_dbg_setfile() and ep_dbg_getfile() returns the value as expected

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 cp ..., see Darwin: shared libraries have the wrong internal name

Debug File JavaScript Code

To get access to these methods, we have some edits to make:

  • $PTII/node_modules/@terraswarm/gdp/gdpjs/gdpjs.js: add declarations for ep_dbg_getfile() and ep_dbg_setfile() inside @@
    var libep = ffi.Library(GDP_DIR + '/libs/libep.3.0', {
    ...
        'ep_dbg_getfile': ['pointer', []],
        'ep_dbg_setfile': ['void', ['pointer']],
  • $PTII/node_modules/@terraswarm/gdp/index.js: add:
    exports.ep_dbg_getfile = gdpjsSupport.ep_dbg_getfile;
    exports.ep_dbg_setfile = gdpjsSupport.ep_dbg_setfile;
  • In $PTII/vendors/gdp/gdp/test:
    bash-3.2$ cat epTest.js
    var gdpjs = require('@terraswarm/gdp');

    gdpjs.ep_dbg_setfile(new Buffer(42));

    var f = gdpjs.ep_dbg_getfile();

    console.log("f: " + f);
    console.log(f);
    bash-3.2$ node epTest.js
    f:
    <Buffer@0x104018df8 >
    bash-3.2$

We get the buffer back?

Debug Analysis

In ep_dbg.c: DebugFile is declared as a file static variable:

FILE            *DebugFile;

The library that is loaded is $PTII/node_modules/@terraswarm/gdp/libs/libep.3.0.dylib. To see this, move that file to a temporary location and run.

bash-3.2$ nm $PTII/node_modules/@terraswarm/gdp/libs/libep.3.0.dylib  | grep DebugFile
000000000000d210 S _DebugFile

The nm man page says: "S (symbol in a section other than those above)"

Using -m gives us more information:

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 ep_dbg_ methods from the libgdp functions, we are getting different library and symbol.

Debug Solution

The 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 gdpjs.js:

//var libep = ffi.Library(GDP_DIR + '/libs/libep.3.0', {                                          
var libep = ffi.Library(GDP_DIR + '/libs/libgdp.0.7', {

Segfault

bash-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 binary is named ggdb and is a PITA to install. After installation, running ggdb node and then:

(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 libs/libgdp.dylib can't find libep.so.3.0

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 install_name_tool program:

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 install_name_tool is run, then ggdb node, r simple_reader_01.js will find the shared library.

The following change to gdp/Makefile will run @@install_name_tool under Mac OS X:

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 numbers

Under Mac OS X, in ggdb node, r simple_reader_01.js does not print any line numbers in the stack trace:

(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 gdp/gdp/Makefile and use -ggdb instead of -g.

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:

  1. Updating gdp/ep/Makefile and using -ggdb instead of -b
  2. Updating gdp/gdp/Makefile and gdp/ep/Makefile and commenting out the O= line
    #O=             -O  
  3. Running
    (cd gdp/ep; make clean; make; cd ../gdp; make clean; make)
  4. Give us better results:
    rogram received signal SIGABRT, Aborted.
    0x00007fff92d20f06 in __pthread_kill () from /usr/lib/system/libsystem_kernel.dylib
    (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 0x0000000101fc6500 in ep_assert_failure (type=0x10319d920 "require",
    file=0x10319e6e7 "gdp_gcl_ops.c", line=646, msg=0x10319d8a0 "%s") at ep_assert.c:88
    #4 0x000000010318f96a in ?? () from /Users/cxh/ptII/vendors/gdp/gdp/gdp/libgdp.so.0.5
    #5 0x00007fff5fbfe940 in ?? ()
    #6 0x00001355191a9a40 in ?? ()
    #7 0x0000000102804000 in ?? ()
    #8 0x00000000a40c040d in ?? ()
    #9 0x0000000103305e20 in ?? ()
    #10 0x00000001033071e0 in ?? ()
    #11 0x0000000000000000 in ?? ()
    (gdb)
  5. In the above, we can see that line 646 in gdp_gcl_ops.c is throwing an assertion, but we might as well recompile the GDP JavaScript interface without optimization and with -ggdb
  6. Editing gdp/lang/js/Makefile and commenting out the O= line and using -ggdb instead of -g, then make clean; make yields:
    (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 0x0000000101fc6500 in ep_assert_failure (type=0x10319d920 "require",
    file=0x10319e6e7 "gdp_gcl_ops.c", line=646, msg=0x10319d8a0 "%s") at ep_assert.c:88
    #4 0x000000010318f96a in ?? () from /Users/cxh/ptII/vendors/gdp/gdp/gdp/libgdp.so.0.5
    #5 0x00007fff5fbfe940 in ?? ()
    #6 0x00000d743b1a9a40 in ?? ()
    #7 0x0000000102804000 in ?? ()
    #8 0x00000000a40c040d in ?? ()
    #9 0x0000000103305e80 in ?? ()
    #10 0x0000000103201ab0 in ?? ()
    #11 0x0000000103803da0 in ?? ()
    #12 0x000000010283ee98 in ?? ()
    #13 0x00007fff5fbfe980 in ?? ()
    #14 0x0000000103189172 in gdp_gcl_read (gcl=0x103803da0, recno=4347402928,
    datum=0x103305e80) at gdp_api.c:456
    Backtrace stopped: frame did not save the PC
    (gdb)

GDP_ASSERT_GOOD_GCL assertion

In gdp_gcl_ops.c, line 646 is marked:

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

  1. Edit gdp/ep/Makefile, gdp/gdp/Makefile and gdp/lang/js/Makefile and make these changes
    1. Comment out the O= line:
      #O=     -O
    2. Replace -g with -ggdb:
      COPTS=  ${PG} -ggdbçç ${WALL} $O ${STD}
  2. In gdp/gdp/Makefile, add lines to run install_name_tool:
    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
  3. Build:
    cd gdp; make
  4. Create a log, note the name
    bash-3.2$ ./apps/gcl-create -k none -s ealmac23.local myLog3
    Created new GCL cHL47Jlv6t9sc74PjV1Gist_PcTT1HnibulAXA8OocI
            on log server ealmac23.local
    exiting with status OK
    bash-3.2$
  5. Build the GDP JavaScript interface:
    cd lang/js; make
  6. cd to gdp/lang/js/apps and edit simple_reader_01.js and update gclname_arg with the value from the gcl-create command above:
    var gclname_arg = "cHL47Jlv6t9sc74PjV1Gist_PcTT1HnibulAXA8OocI"
  7. Start up gdb (See How to install gdb debugger under Mac OS X):
    ggdb node
  8. Run the script:
    r simple_reader_01.js
  9. It might take a few runs to get a stack trace, but eventually running where will show:
    (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 0x0000000101fc6500 in ep_assert_failure (type=0x10329d920 "require",
    file=0x10329e6e7 "gdp_gcl_ops.c", line=646, msg=0x10329d8a0 "%s") at ep_assert.c:88
    #4 0x000000010328f96a in ?? () from /Users/cxh/ptII/vendors/gdp/gdp/gdp/libgdp.so.0.5
    #5 0x00007fff5fbfe940 in ?? ()
    #6 0x00002b4d331ab000 in ?? ()
    #7 0x0000000102804000 in ?? ()
    #8 0x00000000a40c040d in ?? ()
    #9 0x0000000103306310 in ?? ()
    #10 0x0000000103003cd0 in ?? ()
    #11 0x0000000000000000 in ?? ()
    (gdb)
  10. In gdp_gcl_ops.c, line 646 is marked:
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);
 

Solution

It turns out that the problem was that the declaration for gdp_gcl_open was incorrect.

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 deref() on gclPtrPtr was returning a different value

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]],

Debugging

Debugging gdpd

Use

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 gdp.js had

 var libgdp = ffi.Library('./libgdp.1.0', {
  'gdp_init': [ 'ulong', [ 'string' ] ],
  'log_view_ls': [ 'int', [ ] ]
 })

The problem is with the ./. The fix is to do run node gdp.js in gdp/libs after running make

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 endlessly

Now 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)

host 2468 makes no sense.

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 127.0.0.1:2468

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 item

To: 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 script

gdp/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 Frameworks

Found 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.

Subscription

As 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 Overview

Cape 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 Accessor

cd $PTII
mkdir node_modules
npm install @terraswarm/gdp

Run without Subscription

To test that the code other than GDPLogSubscribe works, we run a Node Composite Accessor that does not subscribe: ((cd $PTII/org/terraswarm/accessor/accessors/web/gdp/test/auto; node ../../../hosts/node/nodeHostInvoke.js -timeout 6000 gdp/test/auto/GDPLogCreateAppendReadJS)

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 $PTII/ptolemy/actor/lib/jjs/modules/gdp/test/auto/GDPLogCreateAppendReadJS.xml

Run With Subscription

Next, run the Node Composite Accessor that does subscription: (cd $PTII/org/terraswarm/accessor/accessors/web/gdp/test/auto; node ../../../hosts/node/nodeHostInvoke.js -timeout 6000 gdp/test/auto/GDPLogSubscribeJS)

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_gcl_open() is occurring. A log is not being created because it already exists.

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 subscribe() method in gdp.js. The problem here is that we don't return from read_gcl_records()

node_modules/gdp/gdp.js:subscribe(): about to call read_gcl_records()

In gdp.js, the subscribe() function looks like:

    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 Files

A review of files is in order:

$PTII/ptolemy/actor/lib/jjs/modules/gdp/test/auto/GDPLogSubscribe.xml
The Cape Code Model, which runs in vergil
$PTII/org/terraswarm/accessor/accessors/web/gdp/test/auto/GDPLogSubscribeJS.js
Code generated from GDPLogSubscribe.xml. To run it, use: (cd /Users/cxh/ptII/org/terraswarm/accessor/accessors/web/gdp/test/auto; node ../../../hosts/node/nodeHostInvoke.js -timeout 6000 gdp/test/auto/GDPLogSubscribeJS)
$PTII/org/terraswarm/accessor/accessors/web/gdp/GDPLogSubscribe.js
The accessor definition shared between the Cape Code and Node accessor hosts.
$PTII/org/terraswarm/accessor/accessors/web/hosts/node/node_modules/@accessors-modules/gdp/gdp.js
The gdp module that is found by the Node Accessor Host.
$PTII/node_modules/@terraswarm/gdp/gdpjs/gdpjs.js
The version of gdpjs.js that is found by Node when Node reads var gdpjs = require('@terraswarm/gdp'); in gdp.js. Important: gdpjs must be installed with:
cd $PTII
npm install vendors/gdp/gdp/lang/js
$PTII/vendors/gdp/gdp/lang/js/gdpjs/gdpjs.js
The master copy of gdpjs.js that is read by npm install .... For development and debugging, edit $PTII/node_modules/@terraswarm/gdp/gdpjs/gdpjs.js, and then before running npm install ..., update the master copy with
cp $PTII/node_modules/@terraswarm/gdp/gdpjs/gdpjs.js $PTII/vendors/gdp/gdp/lang/js/gdpjs/gdpjs.js
$PTII/node_modules/@terraswarm/gdp/libs
Shared libraries loaded by gdpjs.js. libgdpjs contains some glue code for the interface.

Subscription Analysis

See GDP JavaScript Callbacks -> Subscription Analysis?.

Subscription Callbacks

See GDP JavaScript Callbacks -> Subscription Callbacks?.

Calling the C-based subscribe() function

It could be that we need to call the C-based subscribe() function.

gdpjs.js:

    // 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 gdpjs.js that call gdp_gcl_subscribe() and one that calls gdp_gcl_multiread():

// 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;
}
 

do_multiread() calls the last one:

   if (subscribe) {
        //C             // start up a subscription                                                
        estat = gdp_gcl_subscribe_no_timeout_no_callback_js(
            gclh, firstrec, numrecs);

Subscription as a separate process

Interestingly, 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.

  1. Edit org/terraswarm/accessor/accessors/web/gdp/test/auto/GDPLogCreateAppendReadJS.js and modify JavaScriptGDPLogName so that it does not call Math.random(). Instead, have it create a log with a fixed name, such as ptolemy.actor.lib.jjs.modules.gdp.test.auto.GDPLogSubscribeJS.yourlogin7.
  2. Edit org/terraswarm/accessor/accessors/web/gdp/test/GDPLogSubscribeOnlyJS.js and set the logName parameter to the name of the log set above.
  3. Invoke the Append Composite Accessor: (cd $PTII/org/terraswarm/accessor/accessors/web/gdp/test/auto; node ../../../hosts/node/nodeHostInvoke.js -timeout 600000 gdp/test/auto/GDPLogCreateAppendReadJS) >& /tmp/append7.txt &
  4. Invoke the Subscribe Composite Accessor: (cd $PTII/org/terraswarm/accessor/accessors/web/gdp/test/auto; node ../../../hosts/node/nodeHostInvoke.js -timeout 600000 gdp/test/GDPLogSubscribeOnlyJS)
  5. The Subscribe Composite Accessor will print out the values that are appended by the Append Composite Accessor.

Problems:

  • The append and subscribe accessors are not in the same accessor.
  • The output is being printed, not sent to the output port

Getting the Next Data

The issue here is that GDPLogSubscribe.js calls log.subscribe(), which could return some data, and then loops and calls log.getNextData():

    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 log.getNextData() is unimplemented. log.subscribe() will get some data, but then we need to get data forever from log.getNextData().

Edit - History - Print - Recent Changes - Search
Page last modified on November 04, 2016, at 03:33 PM