pool-get.c

Introduction

pool-get.c is probably the simplest introduction to programming FramerD. It does nothing more than open the pool specified on the command-line, and retrieve the value associated with the OID specified on the command-line. A simple invocation (against the data you created in the Test Server Setup) looks like this:

pool-get atut@defiant @/atut/0

And produces this output:

[03:17:14 MIT FramerD library 1.0 (c) 1994-1999, built Jun  7 1999]
[03:17:14 Session id=framerd tlilley@defiant /PID:2424 /OS:i686-unknown-linux /Compiled:Jun  7 1999 /Started:Mon Jun  7 03:17:14 1999]
[03:17:14 Added pool atut@defiant]
The OID @/atut/0 in the pool atut@defiant has the value:
"a simple OID value"
      

Now, using the OID you marked earlier when you were creating and adding data, go ahead and try using a literal OID (note that this literal OID must be the one you got as the output from fdscript's "allocate-oid" command, combined with the information found in the #POOL message from fdscript when you connected to the pool in the setup phase.

pool-get atut@defiant @375ae87e/20020

Your output should be the same as the previous invocation (except, of course, for the timestamps).

Source Commentary

pool-get.c itself is so small and elegant that it seems a shame to clutter it with extensive commentary. Heck, I felt bad just adding the usage message! Instead, we'll explore it line-by-line here. There are horizontal rules between each function call (line of the original program) to clarify the context of the discussion.


Of course, to do anything, you'll have to include the FramerD include files :-) Fortunately, they're nicely bundled through one file:

#include <framerd/framerd.h>
      

The first meaningful statement in the program is the call to void fd_initialize_framerd(void) [src/odb/libframerd.c], which does the basic initialization of all of the FramerD library components. This call is, of course, necessary for any subsequent FramerD work.

fd_initialize_framerd();
      

NOTE: Obviously, it's important to call this initializer if you're doing anything with the FramerD libraries, like OID or DType manipulation. What may not strike you, though, when you go to write a simple little test program to exercise fd_fprintf, for example, is that you have to put this call in for any program using the FramerD libraries! We wrote a simple test program that contained nothing more than a single call to fd_fprintf to display the time, and were baffled when it consistenly printed out two copies of our message, regardless of what we put in the format string. Once the lightbulb went on and we inserted a call to fd_initialize_framerd, things returned to normal :-) The moral of the story is: be careful out there.


Next is the call to fd_use_pool fd_use_pool(char * c) [src/odb/odb.c], which opens a file pool, or connects to a network pool server, depending on the pool name given it. If the pool name is in the form server@host, the system treats it as a network pool server, otherwise it treats it as a pool file.

fd_use_pool(pool);
      

Note that the call to fd_use_pool has the side effect of registering the pool's name in a hashtable that the FramerD libraries use to map logical OIDs to literal OIDs. The internal function parse_oid_ref [src/cons/io.c] uses this hashtable to resolve an OID string into a 64-bit OID structure. Therefore, if you haven't mounted the pool before calling any functions which attempt to parse OID strings, logical OIDs won't resolve properly (the program will die with an unhandled exception: "No logical OIDs found"). The version of pool-get.c shipped with the framerd-1.0 distribution calls fd_arg2lisp on the OID string before calling fd_use_pool, and thus will not properly recognize logical OIDs. The pool-get.c we're dissecting here, however, has this corrected.


Next, the call to fd_lisp fd_arg2lisp(u8char *string) [src/cons/io.c] takes the string OID representation passed in on the command line, and converts it into a LISP structure containing the OID. Internally, the function calls parse_atom, then parse_oid_ref to accomplish this.

oid=fd_arg2lisp(oid_str);

Note that this function will throw the exception "No logical OIDs defined" if you pass it a logical OID and the pool named in the logical OID hasn't been mounted with fd_use_pool.

NOTE: Apparently, fd_arg2lisp likes to modify the contents of the string you pass it during its parsing. Thus, if you pass it a constant string, you're asking for a seg fault or GPF. This code does not work:

u8char * oid_str = "@/test/0";
lisp oid = fd_arg2lisp( oid_str );
      

But this code, which copies the string into a dynamically-allocated char array, does work:

u8char * oid_str = (u8char *) malloc( (strlen( "@/test/0" ) + 1) * sizeof( u8char ) );
strcpy( oid_str, "@/test/0" );
lisp oid = fd_arg2lisp( oid_str );
      

(Note that lisp is effectively the same as fd_lisp, and is described in the C Manual for FramerD.)


The invocation of the macro lisp oid_value(lisp oid) [include/framerd/odb.h] resolves the OID and retrieves whatever is stored in the "body" of the DType as a LISP structure. Thus, if the value is more than a simple datum, you will receive the full, complex value.

value=oid_value(oid);

oid_value is actually a wrapper around wrappers :-), implemented as C macros and, eventually, function calls into the FramerD library. I suggest you study the source to divine exactly what's happening, but, in brief, oid_value is a macro which either locks the OID, then evaluates it, in a multi-threaded build, or simply evaluates the OID directly, in a single-threaded build. In either case, oid_value checks to make sure the OID is valid, and has a value. Otherwise it throws an exception.


The last series of calls are to FramerD's modified output functions, void fd_fprintf(FILE *f, char *format_string, ...) [src/os/fdprintf.c], and void fd_pprint_lisp(fd_lisp x, FILE *stream, int width) [src/cons/io.c]. The fd_fprintf function is a replacement for the standard IO library's fprintf, supporting internationalization and some extensions to integrally print FramerD LISP objects. The fd_pprint_lisp function is a simple pretty-printer for LISP objects.

fd_fprintf(stdout,"The OID %q in the pool %s has the value:\n",oid,argv[1]);
fd_pprint_lisp(value,stdout,40);
fd_fprintf(stdout,"\n");
return 0;
      

The fd_fprintf is a simple wrapper around do_printf [src/os/fdprintf.c]. I encourage you to read do_printf closely to make sure you understand how it handles your data.

void fd_printf(fd_string_stream s, char *format_string, ...) (and its derivatives, void fd_fprintf(FILE *f, char *format_string, ...), and void fd_xprintf(char *fstring)] supports the following extended formatting characters:

Building a pool-get.c Clone

So, you've successfully dissected pool-get.c, and want to retype it and build it in your own directory. That's simple enough (under Linux 2.0.36, Debian 2.1 (slink), anyway). Here's a typical command-line for compiling pool-get.c to pool-get on a GNU-ified Unixish system:

gcc pool-get.c -o pool-get -L/usr/local/lib -L/usr/lib -lframerd -ldtypes -lreadline -lpthread
      

Apps that use the FramerD core require libframerd and libdtypes, at a minimum. On systems where FramerD comes with GNU Readline support compiled in, you'll also need to link to libreadline. Finally, on systems where you've built FramerD with pthreads (multithreading under UNIX) support, you'll need to link in libpthread, as well.

(NOTE: on our test system (Linux 2.0.36 Debian 2.1 (slink), gcc 2.7.2.3, GNU ld 2.9.1), it seems that the order of the command-line arguments is, indeed important. So, the command line given above works as specified, but moving the source file and -o pool-get specified to the end of the line seemed to not work. I'm quite sure this is explained adequately in the GNU gcc and ld docs. Have you seen the size of those docs?)

Of course, this is only a very simplistic treatment of the libraries and options available for compiling FramerD applications. Once I understand them all, I'll be happy to explain them to you :-)


Tripp Lilley
Last modified: Mon Jun 7 19:13:35 EDT 1999