i've thought more about what steve said earlier and i think we might want
to use a simple timestamp instead of human-readable 8601 timestamps.  
there are libraries that handle standard 8601 date strings but i can't 
believe that it's faster than atoi().  we'll see .. i'll do some 
benchmarks later.

i wanted to outline where i'm going with ganglia 3 as far as the overall 
design and to share a cool little trick.  i'll start with the cool trick.

one concern i have with a non-threaded design is blocking.  of course
we'll use non-blocking i/o but there's still the metric collection
functions.  if we have a function that gets stuck or is in an infinite
loop then it could gum up the works. (actually even our current design
w/threads can block too).

one solution is to use sigsetjump and siglongjump.  this code snippet 
runs on linux, cygwin, solaris, macos x (i've tested it).  it _seems_ 
portable.

-------- code snippet ------------------
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include <unistd.h>

sigjmp_buf jmpbuf;

/* My signal handler */
void
sig_alrm( int signo )
{
  /* Make bad_function look like it returned 1 */
  siglongjmp(jmpbuf, 1);
}  

/*
 * I'm a bad function that just blocks forever
 */
int
bad_function( void )
{
  for (;;)
    {
      fprintf(stderr,"bad_function running and running\n");  
    }
}

int
main ( void )
{
  signal(SIGALRM, sig_alrm);

  /* Give the bad_function 2 secs to run */
  alarm(2);

  if( sigsetjmp(jmpbuf, 1) )
    {
      /* We are returning from a siglongjmp */
      fprintf(stderr,"\nTimeout\n");
      return 1;
    }

  bad_function();

  /* Turn off the alarm */
  alarm(0);
  return 0;
}
--------- end code snippet ---------------

we could use this approach to put a boundary on the amount of time they 
get to run.  it they exceed the time, an alert is sent and gmond keeps 
right on chugging.  we have to be smart though since on many operating 
systems use SIGALRM for sleep(), etc.  we'll see.

about the overall design of ganglia.  this is what i propose and i'm 
looking for feeedback.  

g3mond -
  acts just like a deaf 2.x gmond.  it just loads all the metric modules
  and send measurements on the wire.  it will also have
  a local unix socket open for other apps/daemons to bootstrap the 
  registered metric attributes.  this will use the xml-> data functions 
  and is necessary to allow condensed network messages to be sent when 
  modules are obiquitous.

g3listend -
  acts just like a mute 2.x gmond.  it just listens to all the traffic 
  from one or more data sources, saves it, and exports it in different 
  formats (xml, ldif, sexpressions).  we'll start with xml alone (since
  it's already written :).  
  output modules will pass a file descriptor, callbacks to tree foreach
  which recurses the tree structure. 

if you run g3mond with a single data source being a multicast channel and
g3listend listening to the same multicast channel you have a 2.x gmond.  
i don't want to lock people into multicast (although i personally think
it's the best way to do business) in g3.  support for tcp and unicast udp
will be there (it's already in the library).

g3rrdd -
  it just listens to one or more data sources and saves the data 
  to round-robin databases.  (it could also be made to "serve"
  historical images but i'm not sure it that is wise or not.  thoughts?)

if you run g3xmld, with multiple data sources (to other g3xmld for 
example) and g3rrdd on a machine.. you have a 2.x gmetad.

g3sqld -
  it just listen to one or more data sources and save the data to a 
  sql database (i haven't written this.. i'm just throwing it out there).

all apps/daemons will get there configuration information from a single 
/etc/ganglia.conf configuration file which i would like to have written 
in..  you guessed it.. XML.  again it'll just use the tree library.  it 
would look something like.

<daemon name="g3listend">
  <section name="tranport">
    <module name="g3XML" path="/var/lib/g3/output/g3XML.so"/>
    <module name="globus_LDIF" path="/var/lib/g3/output/globus.so"/>
  </section>
  <section name="input">
    <source name="Cluster A" ip="1.2.1.2" port="8649" format="XML" />
    <source name="Cluster B" ip="1.2.1.4" port="8649" format="XML" />
  </section>
  <section name="output">
    <export name="ganglia_port" protocol="TCP" port="8649" format="ganglia_XML" 
/>
    <export name="globus_port"  protocol="TCP" port="8651" 
format="globus_LDIF"/>
  </section>
</daemon>
<daemon name="g3mond">
  <section name="transport">
    <module name="Sexp" path="/var/lib/g3/output/g3sexp.so"/>
  </section>
  <section name="metrics">
    <module_dir name="g3 dir" path="/var/lib/ganglia/modules"/>
    <module name="Single Module" path="/home/foobar/special/foo.so"/>
  </section>
  <section name="output">
    <export name="Wire" protocol="UDP" ip="239.2.11.71" port="8649" 
    format="Sexp"/>
  </section>
</daemon>

i just made all that XML up as an example (it's nothing solid).  the nice
thing is that whatever the format it can be slurped in very easily.  the
only assumption the tree library makes is that:

  1. all tags have at least one attribute
  2. the first attribute is the index attribute
  3. the value of the attribute and the value of the tag combined must be 
     unique for each level of the xml tree.

that's it.  it doesn't enforce any more structure than that so it'll 
handle many different xml sources.

does this seem like a sane design?  since we are moving to an event-driven 
model i thought i was wise to break out the functions into separate 
daemons.

what do you guys think?  

the tree library also allows g3listend to quickly bootstrap from a data source.

i'll stop rambling now and get back to the code.  what are your guys 
schedules looking like in the next few weeks?  can any of your contribute 
code time to g3?  i feel like i'm almost to the point that asking for some 
time wouldn't be a waste of your time.
-- 
matt


Reply via email to