two new modules, remote_node and remote_pool
authorTero Marttila <terom@fixme.fi>
Fri, 06 Jun 2008 03:24:55 +0300
changeset 9 fb6632e6c1bb
parent 8 4d38ccbeb93e
child 10 9daa832ab9c4
two new modules, remote_node and remote_pool

committer: Tero Marttila <terom@fixme.fi>
remote_node.c
remote_node.h
remote_pool.c
remote_pool.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remote_node.c	Fri Jun 06 03:24:55 2008 +0300
@@ -0,0 +1,51 @@
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <assert.h>
+
+#include "common.h"
+#include "render_remote.h"
+#include "remote_node.h"
+
+int remote_node_init (struct remote_node *node_info, const char *hostname, const char *portname) {
+    // zero out the struct
+    memset(node_info, 0, sizeof(*node_info));
+
+    // XXX: currently, this is hardcoded to one, but should be automagically discovered
+    node_info->parallel_renders = 1;
+
+    // lookup the host:port
+    portname = portname ? portname : RENDER_PORT_NAME;
+    
+    // XXX: stat it and look for a PF_UNIX socket!
+    
+    // PF_INET
+    
+    struct addrinfo hints, *results, *result;
+
+    memset(&hints, 0, sizeof(hints));
+    hints.ai_socktype = SOCK_STREAM;
+    hints.ai_flags = AI_ADDRCONFIG;     // attempt to get a working address as the first result
+
+    int err = getaddrinfo(hostname, portname, &hints, &results);
+    
+    if (err != 0) {
+        error("getaddrinfo: [%s].%s: %s", hostname, portname, gai_strerror(err));
+
+        return -1;
+    }
+    
+    assert(results != NULL); // we expect at least one result
+
+    // XXX: only use the first result, discard the rest.
+    result = results;
+    memcpy(&node_info->addr, result->ai_addr, result->ai_addrlen);
+
+    freeaddrinfo(results);
+    
+    // success!
+    node_info->valid = 1;
+    return 0;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remote_node.h	Fri Jun 06 03:24:55 2008 +0300
@@ -0,0 +1,42 @@
+#ifndef REMOTE_NODE_H
+#define REMOTE_NODE_H
+
+#include <sys/socket.h>
+
+/*
+ * Information about a single remote render node.
+ */
+
+struct remote_node {
+    int valid;
+
+    /*
+     * Static information
+     */
+
+    // the remote address, note how this can both AF_INET and AF_LOCAL
+    struct sockaddr_storage addr;
+
+    // how many render requests this node can process concurrently
+    int parallel_renders;
+    
+    /*
+     * Dynamic information
+     */
+
+    // how many render requests this node is currently processing
+    int current_load;
+};
+
+/*
+ * Initialize the given remote_node struct to work with the render node at the given host/port.
+ *
+ * Portname may also be NULL, in which case the default port is used.
+ *
+ * Note that this is a blocking function, and should only be called at startup.
+ *
+ * returns nonzero on error, zero on success.
+ */
+int remote_node_init (struct remote_node *node_info, const char *hostname, const char *portname);
+
+#endif /* REMOTE_NODE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remote_pool.c	Fri Jun 06 03:24:55 2008 +0300
@@ -0,0 +1,119 @@
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#include "remote_pool.h"
+#include "common.h"
+
+void remote_pool_init (struct remote_pool *pool_info) {
+    memset(pool_info, 0, sizeof(*pool_info));
+}
+
+int remote_pool_add (struct remote_pool *pool_info, const char *hostname, const char *portname) {
+    int i;
+    struct remote_node *node_info = NULL;
+    
+    // find a free remote_node entry and store its pointer in node_info
+    for (i = 0; i < REMOTE_POOL_MAX; i++) {
+        if (!pool_info->nodes[i].valid) {
+            node_info = &pool_info->nodes[i];
+            break;
+        }
+    }
+
+    if (!node_info) {
+        error("remote_pool_add: pool full, consider increasing REMOTE_POOL_MAX");
+        return -1;
+    }
+
+    return remote_node_init(node_info, hostname, portname);
+}
+
+int remote_pool_load (struct remote_pool *pool_info, const char *filename) {
+    // open the file
+    FILE *fh = fopen(filename, "r");
+
+    if (!fh) {
+        perr("remote_pool_load: fopen(%s)", filename);
+        return -1;
+    }
+    
+    // read it in line-by-line
+    char line_buf[POOL_FILE_LINE_LENGTH], *hostname, *portname, *c;
+    
+    // non-ferror error indicator
+    int error_flag = 0;
+
+    while (1) {
+        // read in a line
+        if (!fgets(line_buf, POOL_FILE_LINE_LENGTH, fh)) {
+            perr("remote_pool_load: fgets");
+            break;
+        }
+
+        // strip comments
+        c = strchr(line_buf, '#');
+
+        if (c)
+            *c = '\0';
+        
+        // skip empty lines
+        for (c = line_buf; *c != '\0'; c++)
+            if (!isspace(*c))
+                break;
+
+        if (*c == '\0')
+            continue;
+        
+        // parse
+        if (!parse_hostport(line_buf, &hostname, &portname)) {
+            error_flag = 1;
+            break;
+        }
+
+        // add it to the pool
+        if (remote_pool_add(pool_info, hostname, portname)) {
+            error_flag = 1;
+            break;
+        }
+    }
+    
+    // pick up ferrors if otherwise fine
+    error_flag = error_flag || ferror(fh);
+    
+    // close the fd
+    fclose(fh);
+    
+    // error return?
+    if (error_flag)
+        return -1;
+    
+    return 0;
+}
+
+struct remote_node *remote_pool_get (struct remote_pool *pool_info) {
+    int i;
+    struct remote_node *node_info = NULL;
+
+    // find a the appropriate remote_node entry and store its pointer in node_info
+    for (i = 0; i < REMOTE_POOL_MAX; i++) {
+        if (pool_info->nodes[i].valid && (node_info == NULL || pool_info->nodes[i].current_load < node_info->current_load)) {
+            node_info = &pool_info->nodes[i];
+        }
+    }
+
+    // either NULL or the right remote_info
+    return node_info;
+}
+
+int remote_pool_size (struct remote_pool *pool_info) {
+    int i, size = 0;
+
+    for (i = 0; i < REMOTE_POOL_MAX; i++) {
+        if (pool_info->nodes[i].valid) {
+            size++;
+        }
+    }
+    
+    return size;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/remote_pool.h	Fri Jun 06 03:24:55 2008 +0300
@@ -0,0 +1,51 @@
+#ifndef REMOTE_POOL_H
+#define REMOTE_POOL_H
+
+#include "remote_node.h"
+
+// maximum number of nodes in a remote pool
+#define REMOTE_POOL_MAX 8
+
+// how many bytes long each line in a pool file may be
+#define POOL_FILE_LINE_LENGTH 512
+
+struct remote_pool {
+    // the remote_nodes are part of this struct
+    struct remote_node nodes[REMOTE_POOL_MAX];
+};
+
+/*
+ * Initialize the given remote_pool
+ */
+void remote_pool_init (struct remote_pool *pool_info);
+
+/*
+ * Add a remote_node to the pool, see remote_node_init
+ */
+int remote_pool_add (struct remote_pool *pool_info, const char *hostname, const char *portname);
+
+/*
+ * Adds remote_nodes to the pool based on the contents of the given file
+ *
+ * The format for the file is a set of "<hostname>:<portname>" lines, see
+ * parse_hostport in common.h. Blank lines are skipped, and any comments
+ * prefixed with a '#' char is ignored. Whitespace inside lines is also
+ * ignored.
+ *
+ * Returns however many nodes were added (possibly zero), or -1 on error
+ */
+int remote_pool_load (struct remote_pool *pool_info, const char *filename);
+
+/*
+ * Choose a remote_node from the pool
+ *
+ * Attempts to pick the one that's least busy
+ */
+struct remote_node *remote_pool_get (struct remote_pool *pool_info);
+
+/*
+ * Get the number of remote render nodes in this pool
+ */
+int remote_pool_size (struct remote_pool *pool_info);
+
+#endif /* REMOTE_POOL_H */