You are viewing a plain text version of this content. The canonical link for it is here.
Posted to triplesoup-commits@incubator.apache.org by le...@apache.org on 2007/04/13 08:56:16 UTC
svn commit: r528394 [6/35] - in
/incubator/triplesoup/donations/TRIPLES-3-RDFStore: ./ dbms/ dbms/client/
dbms/client/t/ dbms/dbmsproxy/ dbms/deamon/ dbms/doc/ dbms/include/
dbms/libdbms/ dbms/utils/ doc/ include/ lib/ lib/DBD/ lib/RDFStore/
lib/RDFSto...
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/conf.h
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/conf.h?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/conf.h (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/conf.h Fri Apr 13 01:56:01 2007
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+ * Dirk-Willem van Gulik <di...@webweaving.org>
+ *
+ * NOTICE
+ *
+ * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+ * file you should have received together with this source code. If you did not get a
+ * a copy of such a license agreement you can pick up one at:
+ *
+ * http://rdfstore.sourceforge.net/LICENSE
+ *
+ *
+ * $Id: conf.h,v 1.6 2006/06/19 10:10:22 areggiori Exp $
+ */
+#ifndef _H_CONF
+#define _H_CONF
+
+typedef enum opstypes {
+ T_ERR, T_NONE, T_RDONLY, T_RDWR, T_CREAT, T_DROP, T_ALL
+} tops;
+
+extern const char * op2string(tops op); /* Translate operation level into a string */
+extern tops allowed_ops(u_long ip); /* Return max operations level in dbase for given IP */
+extern tops allowed_ops_on_dbase(u_long ip, char *db); /* Return max operations level in dbase for given IP and db */
+extern const char * parse_config(char * configfile); /* Parse a config file or stdin on '-'. return NULL or an error */
+#endif
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms-allow-all.conf
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms-allow-all.conf?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms-allow-all.conf (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms-allow-all.conf Fri Apr 13 01:56:01 2007
@@ -0,0 +1,13 @@
+# Baseline reject
+<dbase _>
+ order allow,deny
+ deny all from all
+</dbase>
+
+# And then just allow from all
+# to make testing possible.
+#
+<dbase *>
+ order deny, allow
+ allow all from all
+</dbase>
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms.conf
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms.conf?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms.conf (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbms.conf Fri Apr 13 01:56:01 2007
@@ -0,0 +1,89 @@
+# This is a comment, I love comments.
+#
+# BNF:
+# File
+# '<' <dbase> <NAME> '>' block '</' <dbase> '>'
+# NAME
+# ::= \w+
+# Block
+# <order> [by] <deny|allow>,<allow,deny>
+# <allow|deny> [operation] <ops> [from] <spec>
+# ops
+# none | rdonly | rdwr | all
+# spec
+# IP [ [>netmask>] <mask> | '/' <len> ]
+# FQHN [ [<netmask>] <mask> | '/' <len> ]
+# 'all'
+# mask
+# IP | FQHN
+# IP
+# dotted quad
+# FQHN
+# anything DNS
+# len
+# 0 .. 32
+#
+
+
+# test blank lines
+
+
+
+# test record
+#
+<dbase foo>
+ # Order allow,deny or deny,allow
+ order deny,allow
+ # operation levels
+ # none nothng allowed
+ # rdonly just read allowed
+ # rdwr read and write allowed
+ # all read, write and create allowed.
+ #
+ #
+ deny all from all
+ allow rdonly from all
+ allow operation rdwr from 127.0.0.1
+ allow all from 10.0.1.2/8
+ allow none from 10.0.1.2/1
+ allow rdonly from 10.0.1.2/27
+</dbase>
+
+# Base line which gets ALWAYS applied
+#
+<dbase _>
+ order allow,deny
+ deny all from all
+</dbase>
+
+<dbase bar>
+ order allow,deny
+ allow all from all
+ deny rdwr from 1.2.3.4/16
+</dbase>
+
+<dbase tango>
+ deny all from all
+</dbase>
+
+<dbase tango2*>
+ allow all from all
+</dbase>
+
+# Fall through which ONLY gets applied if there
+# are no specific dbase+IP rule was defined.
+#
+<dbase *>
+ order deny,allow
+ allow rdonly from all
+</dbase>
+
+<dbase caffee>
+ order allow,deny
+ allow rdonly from all
+ allow rdwr from 9.8.7.6
+ allow all from 4.5.6.7/24
+ #deny all from www.news.com
+ allow drop from 127.0.0.1
+</dbase>
+
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmscheckconf.8
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmscheckconf.8?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmscheckconf.8 (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmscheckconf.8 Fri Apr 13 01:56:01 2007
@@ -0,0 +1,11 @@
+Config checker
+
+Usage
+
+ ./dbmscheckconf <conffile>
+
+or
+ ./dbmscheckconf <conffile> 'dbase' 'ip|host' ...
+
+and for each dbase and ip or hostname the xs control will be evaluated.
+
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.8
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.8?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.8 (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.8 Fri Apr 13 01:56:01 2007
@@ -0,0 +1,107 @@
+.\"\*
+.\"\* Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+.\"\* Dirk-Willem van Gulik <di...@webweaving.org>
+.\"\*
+.\"\* NOTICE
+.\"\*
+.\"\* This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+.\"\* file you should have received together with this source code. If you did not get a
+.\"\* a copy of such a license agreement you can pick up one at:
+.\"\*
+.\"\* http://rdfstore.sourceforge.net/LICENSE
+.\"\*
+.\"\* Perl 'tie' interface to a socket connection. Possibly to
+.\"\* the a server which runs a thin feneer to the Berkely DB.
+.\"\*
+.\"\* Based on DB_File, which came with perl and UKD which
+.\"\* came with CILS.
+.\"\*/
+.\"
+.Dd November, 2000
+.Dt DBMSD 8
+.Os
+.Sh NAME
+.Nm dbmsd
+.Nd remote
+.Tn DB
+server
+.Sh SYNOPSIS
+.Nm dbmsd
+.Op Fl x
+.Op Fl v
+.Op Fl t
+.Op Fl d
+.Op Fl d Arg dbase directory
+.Op Fl p Arg port number
+.Op Fl p Arg address to bind to
+.Op Fl c configfile
+.Op Fl C configfile
+.Op Fl U
+.Op Fl u userid or username
+.Sh DESCRIPTION
+.Nm dbmsd
+runs on a server machine to service
+.Tn DB
+requests from client machines. Mainly a perl library
+.Pp
+.Pp
+The following options are available:
+.Bl -tag -width Ds
+.It Fl v
+Just print the version number, and exit.
+.It Fl X
+Run in debug mode, does not fork, does not detatch.
+.It Fl t
+Simple command tracing; to stdout
+.It Fl d directory
+Specifies the prefix for the directory to create the *.db files in. When compiled
+with HASHING set; the
+.Nm dbmsd
+will in fact create another level of directories below this.
+.It Fl p Arg port
+Specifies the port number.
+.It Fl b addresss
+Specifies the address to bind the server to. If none is specified the server will listen on
+all addresses (INADDR_ANY).
+.It Fl c configfile
+Use spefified config file (use the -v flag to see default config file). Or use '-' for stdin.
+.It Fl C configfile
+Check the specified config file and exit immediately with ok/not-ok. See also
+,Xref 8 dbmscheckconf
+.It Fl u userid or username.
+Specifies as which user the dbm(s) will be accesses. For sanity
+and security reasons, the server
+uses
+.Xr setuid 2
+to change to that userid (or username) as soon as the relevant
+ports are opened, the loggin is startend and, for forking servers,
+the dbmsd.pid file is writen. If not specified the default
+.Dq nobdoy
+is used.
+.It Fl U
+Specifies no user ID change; the server will run from the user ID
+is was started from (usually root). This counters the
+.Dq -u
+flag above.
+.El
+.Pp
+For example,
+.Dq Li "dbmsd -p 1234 -d /tmp"
+Caused the server to listen to port 1234 (the default) and create
+its Berkely DB files in /tmp (the default).
+.Pp
+The
+.Nm dbmsd
+utility exits 0 on success, and >0 if an error occurs.
+.Sh SEE ALSO
+.Xr DB 3 ,
+.Xr Perl 1
+and
+.Xr perltie 1
+.Sh Author
+Dirk-Willem van Gulik, Alberto Reggiori at STA/ISIS, Joint Research Center Ispra
+for the ParlEuNet project.
+.Sh HISTORY
+The
+.Nm dbmsd
+Started live with the ParlEuNet project.
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.h
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.h?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.h (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/dbmsd.h Fri Apr 13 01:56:01 2007
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+ * Dirk-Willem van Gulik <di...@webweaving.org>
+ *
+ * NOTICE
+ *
+ * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+ * file you should have received together with this source code. If you did not get a
+ * a copy of such a license agreement you can pick up one at:
+ *
+ * http://rdfstore.sourceforge.net/LICENSE
+ *
+ *
+ * $Id: dbmsd.h,v 1.13 2006/06/19 10:10:22 areggiori Exp $
+ */
+#ifndef _H_DBMSD
+#define _H_DBMSD
+
+#include "dbms.h"
+#include "dbms_compat.h"
+#include "dbms_comms.h"
+#include "deamon.h"
+
+#ifdef RDFSTORE_DBMS_DEBUG_TIME
+extern float total_time;
+#endif
+
+extern connection * client_list, *mum;
+extern struct child_rec * children;
+extern fd_set rset,wset,eset,alleset,allrset,allwset;
+extern char * default_dir;
+extern char * dir;
+extern int sockfd,maxfd,mum_pgid,mum_pid,max_dbms,max_processes,max_clients;
+extern char * my_dir;
+extern char * pid_file;
+extern char * conf_file;
+extern int check_children;
+extern dbase * first_dbp;
+
+void select_loop();
+
+/* Some reasonable limit, to avoid running out of
+ * all sorts of resources, such as file descriptors
+ * and all that..
+ */
+#define MAX_CLIENT 2048
+
+/* An absolute limit, above this limit, connections
+ * are no longer accepted, and simply dropped without
+ * as much as an error.
+ */
+#define HARD_MAX_CLIENTS MAX_CLIENT+5
+#define HARD_MAX_DBASE 256
+
+/* hard number for the total number of DBMS-es we
+ * are willing to server (in total)
+ */
+
+#define MAX_DBMS_CHILD 256
+#define MAX_CHILD 32
+#define MAX_DBMS (MAX_DBMS_CHILD * MAX_CHILD)
+
+
+#define SERVER_NAME "DBMS-Dirkx/3.00"
+
+#define SERVER 1
+#define CLIENT 0
+
+/* some connection types... */
+#define C_UNK 0
+#define C_MUM 1
+#define C_CLIENT 2
+#define C_NEW_CLIENT 3
+#define C_CHILD 4
+#define C_LEGACY 5
+
+struct child_rec * create_new_child(void);
+int handoff_fd( struct child_rec * child, connection * r );
+int takeon_fd(int conn_fd);
+connection * handle_new_local_connection( int sockfd , int type);
+connection * handle_new_connection( int sockfd , int type, struct sockaddr_in addr);
+
+#define MX dbms_log(L_DEBUG,"@@ %s:%d",__FILE__,__LINE__);
+#endif
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.c
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.c?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.c (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.c Fri Apr 13 01:56:01 2007
@@ -0,0 +1,746 @@
+/*
+ * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+ * Dirk-Willem van Gulik <di...@webweaving.org>
+ *
+ * NOTICE
+ *
+ * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+ * file you should have received together with this source code. If you did not get a
+ * a copy of such a license agreement you can pick up one at:
+ *
+ * http://rdfstore.sourceforge.net/LICENSE
+ *
+ *
+ * $Id: deamon.c,v 1.26 2006/06/19 10:10:22 areggiori Exp $
+ */
+
+#include "dbms.h"
+#include "dbms_compat.h"
+#include "dbms_comms.h"
+#include "dbmsd.h"
+
+#include "deamon.h"
+#include "handler.h"
+#include "mymalloc.h"
+
+static int going_down = 0;
+int client_counter = 0; /* XX static perhaps */
+
+#ifdef STATIC_BUFF
+static connection * free_connection_list = NULL;
+static int free_connection_keep = 2;
+static int free_connection_keep_max = 4;
+static int free_connection_len = 0;
+#endif
+
+#define PTOK { int i; for(i=0; i<sizeof(cmd_table) / sizeof(struct command_req); i++) if ( cmd_table[i].cmd == r->cmd.token ) { dbms_log(L_DEBUG,"Token at %s:%d %s s=%d,%d",__FILE__,__LINE__, cmd_table[i].info,r->cmd.len1,r->cmd.len2); break; }; if(i>=sizeof(cmd_table) / sizeof(struct command_req)) dbms_log(L_DEBUG,"Token at %s:%d %s %d,%d",__FILE__,__LINE__, "**UNKOWN**",r->cmd.len1,r->cmd.len2); }
+
+void
+close_connection ( connection * r )
+{
+ /* assert(r->clientfd); */
+ FD_CLR(r->clientfd,&allwset);
+ FD_CLR(r->clientfd,&allrset);
+ FD_CLR(r->clientfd,&alleset);
+ close(r->clientfd);
+ r->clientfd = 0;
+
+ /* shutdown(r->clientfd,2); */
+
+ if (r->sendbuff != NULL) {
+ myfree(r->sendbuff);
+ r->sendbuff = NULL;
+ };
+
+ if (r->recbuff != NULL) {
+ myfree(r->recbuff);
+ r->recbuff = NULL;
+ };
+
+ r->send = r->tosend = 0;
+ r->gotten = r->toget = 0;
+
+ r->close = 2; MX;
+
+#ifdef STATIC_BUFF
+ if (free_connection_len < free_connection_keep) {
+ r->next = free_connection_list;
+ /* assert( free_connection_list != r ); */
+ free_connection_list = r;
+ free_connection_len++;
+ } else
+#endif
+ myfree(r);
+
+ client_counter --;
+
+ return;
+}
+
+void free_connection (connection * r ) {
+
+ if (r->type == C_MUM) {
+ /* connection to the mother lost.. we _must_ exit now.. */
+ if (!going_down)
+ dbms_log(L_FATAL,"Mamma has died.. suicide time for child, fd=%d",r->clientfd);
+ cleandown(0);
+ } else
+ if (r->type == C_CLIENT) {
+ if (r->dbp) {
+ /* check if this is the last child using
+ * a certain database, and clean if such is
+ * indeed the case..
+ */
+ r->dbp->num_cls --;
+ if (r->dbp->num_cls<=0) {
+ dbms_log(L_INFORM,"Child was the last one to use %s, closing",
+ r->dbp->pfile);
+ r->dbp->close = 1; MX;
+ };
+ dbms_log(L_DEBUG,"Connection to client closed");
+ }
+ else {
+ dbms_log(L_WARN,"C_Client marked with no database ?");
+ }
+ } else
+ if (r->type == C_NEW_CLIENT) {
+ /* tough.. but that is about it.. or shall we try
+ * to send a message...
+ *
+ */
+ dbms_log(L_ERROR,"New child closing.. but then what ?");
+ } else
+ if (r->type == C_LEGACY) {
+ dbms_log(L_DEBUG,"Legacy close");
+ } else
+ if (r->type == C_CHILD) {
+#ifdef FORKING
+ dbase * p=0;
+ child_rec * c=NULL;
+ /* we lost a connection to a child.. so try to kill
+ * it and forget about it...
+ * work out which databases are handled by this child..
+ */
+ for(p=first_dbp;p;p=p->nxt)
+ if (p->handled_by->r == r) {
+ if ((c) && (p->handled_by != c))
+ dbms_log(L_ERROR,"More than one child pointer ?");
+ p->close = 1; MX;
+ c = p->handled_by;
+ };
+ if (c==NULL) {
+ dbms_log(L_ERROR,"Child died, but no record..");
+ }
+ else {
+ /* overkill, as we do not even wait for the
+ * child to be clean up after itself.
+ */
+ c->close = 1; MX;
+ if (kill(c->pid,0) == 0) {
+ /* so the child is still alive ? */
+ dbms_log(L_DEBUG,"Sending kill signal (%d) to %d",
+ SIGTERM,c->pid);
+ kill(c->pid,SIGTERM);
+ };
+ };
+#else
+ dbms_log(L_ERROR,"We are non forking, but still see a C_CHILD");
+#endif
+ }
+ else {
+ dbms_log(L_ERROR,"Zapping a rather unkown connection type?");
+ };
+
+ r->type = C_UNK;
+ close_connection(r);
+ return;
+}
+
+void zap ( connection * r ) {
+ connection * * p;
+
+ for ( p = &client_list ; *p && *p != r; )
+ p = &((*p)->next);
+
+ if ( *p == NULL) {
+ dbms_log(L_ERROR,"Connection to zap not found");
+ return;
+ };
+
+ *p = r->next;
+ free_connection(r);
+ }
+
+
+void cleandown( int signo )
+{
+ if (going_down)
+ dbms_log(L_ERROR,"Re-entry of cleandown().");
+
+ going_down = 1;
+
+ shutdown(sockfd,2);
+ close(sockfd);
+
+ /* send a kill to my children
+ */
+ if (!mum_pid)
+ kill(SIGTERM,0);
+
+ close_all_dbps();
+#ifdef FORKING
+ clean_children();
+#endif
+{
+ connection * r;
+ for(r=client_list; r;) {
+ connection * q;
+ q = r; r=r->next;
+ assert(q != r);
+ close_connection(q);
+ }
+}
+
+ /* close connection to mother */
+ if (mum)
+ close_connection(mum);
+
+
+#ifdef RDFSTORE_DBMS_DEBUG_MALLOC
+ debug_malloc_dump(stderr);
+#endif
+#ifdef RDFSTORE_DBMS_DEBUG_TIME
+ fprintf(stderr,"Timedebug: Time waiting=%f, handling=%f network=%f\n",.1,.2,.3);
+#endif
+ if (!mum_pid)
+ unlink(pid_file);
+
+ dbms_log(L_WARN,"Shutdown completed");
+ exit(0);
+ }
+
+void continue_send( connection * r ) {
+ int s;
+
+ if ((r->tosend==0) || ( r->send >= r->tosend)) {
+ dbms_log(L_ERROR,"How did we get here ?");
+ r->close=1; MX;
+ return;
+ };
+
+ s = write(r->clientfd,r->sendbuff+r->send,r->tosend - r->send);
+
+ if ((s<=0) && (errno == EINTR)) {
+ dbms_log(L_INFORM,"Continued send interrupted. Retry.");
+ return;
+ }
+ else
+ if ((s<0) && (errno == EAGAIN)) {
+ dbms_log(L_WARN,"Continued send would still block");
+ return;
+ }
+ else
+ if (s<0) {
+ dbms_log(L_ERROR,"Failed to continue write %s",strerror(errno));
+ r->close=1;
+ return;
+ }
+ else
+ if (s==0) {
+ dbms_log(L_ERROR,"Client closed the connection on us");
+ r->close=1;
+ return;
+ }
+
+ r->send += s;
+ if ( r->send < r->tosend )
+ return;
+
+ r->send = r->tosend = 0;
+
+#ifndef STATIC_SC_BUFF
+ if (r->sendbuff)
+ myfree( r->sendbuff );
+ r->sendbuff = NULL;
+#endif
+
+ FD_CLR(r->clientfd,&allwset);
+ return;
+}
+
+void dispatch( connection * r, int token, DBT * v1, DBT * v2) {
+ int s;
+
+ if ((r->tosend != 0) && (r->send !=0)) {
+ dbms_log(L_WARN,"dispatch, but still older data left to send");
+ goto fail_dispatch;
+ };
+
+ r->iov[0].iov_base = (void *) &(r->cmd);
+ r->iov[0].iov_len = sizeof(r->cmd);
+
+ r->iov[1].iov_base = r->v1.data =
+ (v1 == NULL) ? NULL : v1->data;
+ r->iov[1].iov_len = r->v1.size = r->cmd.len1 =
+ ( v1 == NULL ) ? 0 : v1->size;
+
+ r->iov[2].iov_base = r->v2.data =
+ (v2 == NULL) ? NULL : v2->data;
+ r->iov[2].iov_len = r->v2.size = r->cmd.len2 =
+ ( v2 == NULL ) ? 0 : v2->size;
+
+ r->tosend = sizeof(r->cmd) + r->cmd.len1 + r->cmd.len2;
+ r->send =0;
+
+ r->cmd.token = token;
+ r->cmd.len1 = htonl( r->cmd.len1 );
+ r->cmd.len2 = htonl( r->cmd.len2 );
+
+#ifdef RDFSTORE_DBMS_DEBUG_TIME
+ gettimeofday(&(r->cmd.stamp),NULL);
+#endif
+ /* BUG: we also use this with certain errors, in an attempt to
+ * inform the other side of the error. So it might well be
+ * that we block here... one day...
+ */
+ s=writev(r->clientfd,r->iov,3);
+
+ if (s<0) {
+ if (errno == EINTR) {
+ dbms_log(L_INFORM,"Initial write interrupted. Ignored");
+ s=0;
+ }
+ else
+ if (errno == EAGAIN) {
+ dbms_log(L_INFORM,"Initial write would block");
+ s = 0;
+ }
+ else {
+ dbms_log(L_ERROR,"Initial write error: %s",strerror(errno));
+ goto fail_dispatch;
+ };
+ }
+ else
+ if ((s==0) && (errno != EINTR)) {
+ dbms_log(L_ERROR,"Intial write; client closed connection");
+ goto fail_dispatch;
+ };
+
+ r->send += s;
+ if (r->send == r->tosend) {
+ r->send = 0;
+ r->tosend =0;
+#ifndef STATIC_SC_BUFF
+ if (r->sendbuff)
+ myfree(r->sendbuff);
+ r->sendbuff = NULL;
+#endif
+ }
+ else {
+ int at,i; void * p;
+ /* create a buffer for the remaining data
+ */
+
+#if STATIC_SC_BUFF
+ if (r->tosend-r->send > MAX_SC_PAYLOAD) {
+ dbms_log(L_ERROR,
+ "Secondary write buffer of %d>%d bytes to big",
+ r->tosend - r->send,
+ MAX_SC_PAYLOAD
+ );
+ goto fail_dispatch;
+ };
+#else
+ assert(r->tosend > r->send );
+ r->sendbuff = mymalloc( r->tosend - r->send );
+#endif
+ assert(r->sendbuff);
+
+ if (r->sendbuff == NULL) {
+ dbms_log(L_ERROR,
+ "Out of memory whilst creating a secondary write buffer of %d bytes",
+ r->tosend - r->send
+ );
+ goto fail_dispatch;
+ };
+
+ for(p=r->sendbuff,i=0,at=0; i < 3; i++) {
+ if ( at > r->send ) {
+ memcpy(p, r->iov[i].iov_base,r->iov[i].iov_len);
+ p+=r->iov[i].iov_len;
+ } else
+ if ( at + r->iov[i].iov_len > r->send ) {
+ int offset = r->send - at;
+ int len=r->iov[i].iov_len - offset;
+ memcpy(p, r->iov[i].iov_base + offset, len);
+ p+=len;
+ }
+ else {
+ /* skip, done */
+ }
+ at += r->iov[i].iov_len;
+ };
+
+ /* redo our bookkeeping, as we have moved it all in
+ * just one contineous buffer. We had to copy, as the
+ * v1 and v2's propably just contained pointers to either
+ * a static error string or a memmap file form the DB inter
+ * face; neither which are going to live long.
+ */
+ r->tosend -= s;
+ r->send = 0;
+
+ FD_SET(r->clientfd,&allwset);
+ };
+
+ return;
+
+fail_dispatch:
+ dbms_log(L_WARN,"dispatch failed");
+ r->close=1;MX;
+ return;
+ }
+
+void do_msg ( connection * r, int token, char * msg) {
+ DBT rr;
+
+ rr.size = strlen(msg) +1;
+ rr.data = msg;
+
+ dispatch(r,token | F_SERVER_SIDE, &rr, NULL);
+ return;
+ }
+
+connection *
+handle_new_local_connection(
+ int clientfd, int type
+ )
+{
+ struct sockaddr_in none;
+ none.sin_addr.s_addr = INADDR_NONE;
+ return handle_new_connection(clientfd, type, none);
+}
+
+connection *
+handle_new_connection(
+ int clientfd, int type, struct sockaddr_in addr
+ )
+{
+ connection * new;
+ int v;
+
+ if (client_counter > HARD_MAX_CLIENTS) {
+ dbms_log(L_ERROR,"Max number of clients reached (hard max), completely ignoring");
+ close(clientfd);
+ return NULL;
+ };
+
+ if (client_counter >= max_clients) {
+ connection tmp;
+ tmp.clientfd = clientfd;
+ tmp.close = tmp.send = tmp.tosend = tmp.gotten = tmp.toget = 0;
+ reply_log(&tmp,L_ERROR,"Too many connections fd=%d",clientfd);
+ close(clientfd);
+ return NULL;
+ };
+
+ if ( (v=fcntl( clientfd, F_GETFL, 0)<0) || (fcntl(clientfd, F_SETFL,v | O_NONBLOCK)<0) ) {
+ dbms_log(L_ERROR,"Could not make socket non blocking: %s",strerror(errno));
+ close(clientfd);
+ return NULL;
+ };
+
+ FD_SET(clientfd,&allrset);
+ FD_SET(clientfd,&alleset);
+
+ /* XXX we could try to fill holes in the bit array at this point;
+ * and get max fd as low as possible. But it seems that the OS
+ * already keeps the FDs as low as it can (except for OpenBSD ??)
+ */
+ if ( clientfd > maxfd )
+ maxfd=clientfd;
+
+ /* if still space, use, otherwise tack another
+ * one to the end..
+ */
+#if STATIC_BUFF
+ if (free_connection_list != NULL) {
+ new = free_connection_list;
+ free_connection_list = new->next;
+ free_connection_len --;
+ } else {
+ assert(free_connection_len == 0);
+ if (free_connection_keep < free_connection_keep_max/2)
+ free_connection_keep *= 2;
+ else
+ if (free_connection_keep < free_connection_keep_max)
+ free_connection_keep += 2;
+#endif
+ if ((new = (connection *) mymalloc(sizeof(connection))) == NULL )
+ {
+ dbms_log(L_ERROR,"Could not claim enough memory");
+ close(clientfd);
+ return NULL;
+ };
+#if STATIC_BUFF
+ }
+#endif
+ bzero(new,sizeof(connection));
+ new->next = client_list;
+ client_list = new;
+
+ bzero(new,sizeof(new));
+
+ /* Copy the needed information. */
+ new->clientfd = clientfd;
+
+ new->sendbuff = NULL;
+#ifdef STATIC_SC_BUFF
+ if ((type != C_CHILD))
+ new->sendbuff = (unsigned char *) mymalloc(MAX_SC_PAYLOAD);
+#endif
+ new->recbuff = NULL;
+#ifdef STATIC_CS_BUFF
+ if ((type != C_CHILD))
+ new->recbuff = (unsigned char *) mymalloc(MAX_CS_PAYLOAD);
+#endif
+
+ new->dbp = NULL;
+ new->type = type;
+
+#ifdef TIMEOUT
+ new->start = time(NULL);
+ new->last = time(NULL);
+#endif
+ new->address = addr;
+ new->close = 0;
+ new->send = new->tosend = new->gotten = new->toget = 0;
+
+ client_counter ++;
+ return new;
+}
+
+void final_read( connection * r)
+{
+ r->toget = r->gotten = 0;
+ parse_request(r);
+
+#ifndef STATIC_CS_BUFF
+ if (r->recbuff) {
+ myfree(r->recbuff);
+ r->recbuff = NULL;
+ };
+#endif
+ return;
+}
+
+
+void initial_read( connection * r ) {
+ struct header skip_cmd;
+ int n=0;
+
+ /* we peek, untill we have the full command buffer, and
+ * only then do we give it any attention. This safes a
+ * few syscalls.
+ */
+ errno = 0;
+ n=recv(r->clientfd,&(r->cmd),sizeof(r->cmd),MSG_PEEK);
+
+ if (n<0) dbms_log(L_DEBUG,"Read fd=%d n=%d errno=%d/%s",r->clientfd,n,errno,strerror(errno));
+
+ if ((n < 0) && (errno == EAGAIN)) {
+ dbms_log(L_ERROR,"Again read %s on %d",strerror(errno),r->clientfd);
+ return;
+ }
+ else
+ if ((n <= 0) && (errno == EINTR)) {
+ dbms_log(L_ERROR,"Interruped read %s",strerror(errno));
+ return;
+ }
+ else
+ if (n<0) {
+ if (errno != ECONNRESET)
+ dbms_log(L_ERROR,"Read error %s",strerror(errno));
+ r->close=1;MX;
+ return;
+ }
+ else
+ if (n==0) {
+ dbms_log(L_INFORM,"Client side close on read %d/%s (fd=%d)",
+ errno,strerror(errno),r->clientfd);
+ r->close=1;MX;
+ return;
+ }
+ else
+ if ( n != sizeof(r->cmd) ) {
+ /* lets log this, as we want to get an idea if this actually happens .
+ * seems not, BSD, on high load, SCO.
+ */
+ dbms_log(L_WARN,"Still waitingn for those 5 bytes, gotten LESS");
+ return;
+ }
+ else {
+#ifdef RDFSTORE_DBMS_DEBUG_TIME
+ float s,m;
+ struct timeval t;
+ gettimeofday(&t,NULL);
+ s=t.tv_sec - r->cmd.stamp.tv_sec;
+ m=t.tv_usec - r->cmd.stamp.tv_usec;
+ MDEBUG((stderr,"Time taken %f seconds\n", s + m / 1000000.0 ));
+ total_time += s + m / 1000000.0;
+#endif
+
+ /* check if this is ok ?, if not, do not
+ * touch it with a stick.
+ */
+#if 0
+ if (( (r->cmd.token) & ~MASK_TOKEN ) != F_CLIENT_SIDE ) {
+ reply_log(r,L_ERROR,"Not a client side token..");
+ r->close=1; MX;
+ return;
+ };
+#endif
+ r->cmd.token &= MASK_TOKEN;
+
+ /* set up a single buffer to get the remainder of this
+ * message
+ */
+ r->v1.size= r->cmd.len1 = ntohl( r->cmd.len1);
+ r->v2.size= r->cmd.len2 = ntohl( r->cmd.len2);
+
+ // silly endian check.
+#if 1
+ if (r->v1.size > 2*1024*1024) {
+ reply_log(r,L_ERROR,"Size one to big");
+ r->close=1; MX;
+ return;
+ };
+
+ if (r->v1.size > 2*1024*1024) {
+ reply_log(r,L_ERROR,"Size two to big");
+ r->close=1; MX;
+ return;
+ };
+#endif
+
+#ifndef STATIC_CS_BUFF
+ if (r->recbuff)
+ myfree(r->recbuff);
+ r->recbuff = NULL;
+#endif
+ r->v2.data = r->v1.data = NULL;
+ r->toget = r->gotten = 0;
+
+ if (r->cmd.len1 + r->cmd.len2 > 0) {
+#if STATIC_CS_BUFF
+ if (r->cmd.len1 + r->cmd.len2 > MAX_CS_PAYLOAD) {
+ reply_log(r,L_ERROR,
+ "RQ string(s) to big %d>%d bytes",
+ r->cmd.len1 + r->cmd.len2,
+ MAX_CS_PAYLOAD
+ );
+ r->close=1; MX;
+ return;
+ }
+#else
+ r->recbuff = mymalloc( r->cmd.len1 + r->cmd.len2 );
+#endif
+ if (r->recbuff == NULL) {
+ reply_log(r,L_ERROR,
+ "No Memrory for RQ string(s) %d bytes",
+ r->cmd.len1 + r->cmd.len2);
+ r->close=1; MX;
+ return;
+ };
+ r->v1.data = r->recbuff;
+ r->v2.data = r->recbuff + r->cmd.len1;
+ r->toget = r->cmd.len1 + r->cmd.len2;
+ }
+
+ r->iov[0].iov_base = (void *) &skip_cmd;
+ r->iov[0].iov_len = sizeof( r->cmd );
+
+ r->iov[1].iov_base = r->recbuff;
+ r->iov[1].iov_len = r->toget;
+
+reread:
+ errno = 0;
+ n = readv( r->clientfd, r->iov, 2);
+
+ if ((n<=0) && (errno == EINTR)) {
+ dbms_log(L_INFORM,"Interrupted readv. Ignored");
+ goto reread;
+ }
+ else
+ if ((n<0) && (errno == EAGAIN)) {
+ dbms_log(L_ERROR,"Would block. Even though we peeked at the cmd string. Retry");
+ goto reread;
+ }
+ else
+ if (n<0) {
+ dbms_log(L_ERROR,"Error while reading remainder: (1 %s",strerror(errno));
+ r->close=1; MX;
+ return;
+ }
+ else
+ if (n==0) {
+ dbms_log(L_INFORM,"Read, but client closed");
+ r->close=1; MX;
+ return;
+ };
+
+ assert(n >= sizeof(r->cmd));
+
+ n -= sizeof(r->cmd);
+ r->gotten += n;
+
+ if ( r->gotten >= r->toget) {
+ final_read(r);
+ return;
+ };
+ }
+ /* should not get here.. */
+ return;
+ }
+
+void
+continue_read( connection * r ) {
+ /* fill up the two buffers.. */
+ int s;
+
+ dbms_log(L_VERBOSE,"continued read for %d..",r->toget);
+ errno = 0;
+ s = read( r->clientfd, r->gotten + r->v1.data, r->toget - r->gotten);
+
+ if ((s<=0) && (errno == EINTR)) {
+ dbms_log(L_INFORM,"Interrupted continued read. Ignored");
+ return;
+ }
+ else
+ if (((s<0) && (errno == EAGAIN)) ) {
+ dbms_log(L_ERROR,"continued read, but nothing there");
+ return;
+ }
+ else
+ if (s<0) {
+ dbms_log(L_ERROR,"Error while reading remainder: (2 %s",strerror(errno));
+ r->close=1; MX;
+ return;
+ }
+ else
+ if (s==0) {
+ dbms_log(L_ERROR,"continued read, but client closed connection (%d/%s)",
+ errno,strerror(errno));
+ r->close=1; MX;
+ return;
+ };
+
+ r->gotten +=s;
+
+ if (r->gotten >= r->toget)
+ final_read(r);
+
+ return;
+ }
+
+
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.h
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.h?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.h (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/deamon.h Fri Apr 13 01:56:01 2007
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+ * Dirk-Willem van Gulik <di...@webweaving.org>
+ *
+ * NOTICE
+ *
+ * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+ * file you should have received together with this source code. If you did not get a
+ * a copy of such a license agreement you can pick up one at:
+ *
+ * http://rdfstore.sourceforge.net/LICENSE
+ *
+ *
+ * $Id: deamon.h,v 1.14 2006/06/19 10:10:22 areggiori Exp $
+ */
+#ifndef _H_DEAMON
+#define _H_DEAMON
+
+#include "dbms.h"
+#include "conf.h"
+#include "dbms_comms.h"
+
+#ifdef RDFSTORE_DBMS_DEBUG
+#ifdef RDFSTORE_DBMS_DEBUG_TIME
+extern float total_time;
+
+#define MDEBUG( x ) { \
+ struct timeval t; \
+ struct timezone tz; \
+ gettimeofday(&t,&tz); \
+ fprintf(stderr,"MDEBUG[%5d]: %f: ",getpid(),total_time);\
+ fprintf x ; \
+ fflush(stderr);\
+ }
+#else
+#define MDEBUG( x ) { fprintf(stderr,"MDEBUG[%5d %s]: ",getpid(),getpid()==mum_pid ? "mum" : "cld"); fprintf x ; fflush(stderr); }
+#endif
+
+#else
+#define MDEBUG( x ) { ; }
+#endif
+
+
+#ifdef FORKING
+typedef struct child_rec {
+ int close;
+ struct child_rec * nxt;
+ struct connection * r;
+ int pid; /* pid of the child (for sig detects) */
+ int num_dbs; /* Number of DBS-es assigned sofar */
+ } child_rec;
+#endif
+
+typedef struct dbase {
+#ifdef FORKING
+ struct child_rec * handled_by;
+#endif
+ int sname;
+ int mode;
+ int bt_compare_fcn_type;
+#ifdef STATIC_BUFF
+ char pfile[ MAX_STATIC_PFILE ];
+ char name[ MAX_STATIC_NAME ];
+#else
+ char * pfile;
+ char * name;
+#endif
+ DB * handle;
+#ifdef DB_VERSION_MAJOR
+ DBC * cursor ;
+#endif
+ int lastfd; /* last FD from which a cursor was set */
+ int num_cls; /* Number of Clients served */
+ struct dbase * nxt;
+ int close;
+ } dbase;
+
+typedef struct connection {
+
+ int type; /* one of C_MUM, C_CHILD, ... */
+
+ int clientfd;
+
+ struct sockaddr_in address;
+
+ DBT v1;
+ DBT v2;
+
+ char * sendbuff;
+ char * recbuff;
+
+ struct dbase * dbp;
+
+ struct header cmd;
+ struct iovec iov[3];
+ struct msghdr msg;
+
+ tops op; /* Max operation allowed */
+ int send; /* size of the outgoing block */
+ int tosend; /* bytes send sofar.. */
+
+ int gotten;
+ int toget;
+
+ int close; /* Shall I close the connection ? */
+#ifdef TIMEOUT
+ TIMESPEC start,last;
+#endif
+ struct connection * next;
+ } connection;
+
+typedef struct command_req {
+ unsigned char cmd;
+ char * info;
+ int cnt;
+ void (*handler)(connection * r);
+ tops op;
+ } command_req;
+
+extern struct command_req cmd_table[ TOKEN_MAX ];
+
+#define L_FATAL -2
+#define L_ERROR -1
+#define L_WARN 0
+#define L_INFORM 1
+#define L_VERBOSE 2
+#define L_BLOAT 3
+#define L_DEBUG 4
+
+void reply_log(connection * r, int level, char *fmt, ...);
+void dbms_log(int level, char *fmt, ...);
+void trace(char *fmt, ...);
+
+extern int debug,verbose,trace_on;
+
+#define do_error(r,m) do_error_i(r,m,__FILE__,__LINE__);
+#define do_error2(r,m,e) do_error2_i(r,m,e,__FILE__,__LINE__);
+void do_error_i ( connection * r, char * msg, char *file, int line );
+void do_error2_i ( connection * r, char * msg, int err, char *file, int line );
+
+void dispatch( connection * r, int token, DBT * v1, DBT * v2);
+
+void clean_children( void );
+void cleanmost( void );
+void cleandown( int signo );
+
+void zap ( connection * r );
+void zap_dbs( dbase * q );
+#ifdef FORKING
+void zap_child( child_rec * r);
+#endif
+
+void close_connection ( connection * r );
+void free_connection ( connection * r );
+void continue_send( connection * r );
+void final_read( connection * r) ;
+void initial_read( connection * r );
+void continue_read( connection * r );
+
+extern int client_counter;
+
+#endif
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.c
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.c?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.c (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.c Fri Apr 13 01:56:01 2007
@@ -0,0 +1,1621 @@
+/*
+ * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+ * Dirk-Willem van Gulik <di...@webweaving.org>
+ *
+ * NOTICE
+ *
+ * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+ * file you should have received together with this source code. If you did not get a
+ * a copy of such a license agreement you can pick up one at:
+ *
+ * http://rdfstore.sourceforge.net/LICENSE
+ *
+ *
+ * $Id: handler.c,v 1.48 2006/06/19 10:10:22 areggiori Exp $
+ */
+
+#include "dbms.h"
+#include "dbms_comms.h"
+#include "dbms_compat.h"
+#include "dbmsd.h"
+
+#include "deamon.h"
+#include "mymalloc.h"
+#include "handler.h"
+#include "children.h"
+#include "pathmake.h"
+
+#include "rdfstore_flat_store.h"
+
+dbase * first_dbp = NULL;
+
+#ifdef STATIC_BUFF
+static dbase * free_dbase_list = NULL;
+static int free_dbase_list_len = 0;
+static int free_dbase_list_keep = 2;
+static int free_dbase_list_max = 8;
+#endif
+static int dbase_counter = 0;
+
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_dbms_compare_int(
+ const DBT *a,
+ const DBT *b );
+#else
+static int rdfstore_backend_dbms_compare_int(
+ DB *file,
+ const DBT *a,
+ const DBT *b );
+#endif
+
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_dbms_compare_double(
+ const DBT *a,
+ const DBT *b );
+#else
+static int rdfstore_backend_dbms_compare_double(
+ DB *file,
+ const DBT *a,
+ const DBT *b );
+#endif
+
+
+char * iprt( DBT * r ) {
+ static char tmp[ 128 ]; int i;
+ if (r==NULL)
+ return "<null>";
+ if (r->data==NULL)
+ return "<null ptr>";
+ if (r->size < 0 || r->size > 1024*1024)
+ return "<weird size>";
+
+ for(i=0;i< ( r->size > 127 ? 127 : r->size);i++) {
+ int c= ((char *)(r->data))[i];
+ tmp[i] = ((c<32) || (c>127)) ? '.' : c;
+ };
+
+ tmp[i]='\0';
+ return tmp;
+ }
+
+char * eptr( int i ) {
+ if (i==0)
+ return "Ok ";
+ else
+ if (i==1)
+ return "NtFnd";
+ else
+ if (i==2)
+ return "Incmp";
+ else
+ if (i>2)
+ return "+? ";
+ else
+ return "Fail ";
+ }
+
+static int _dbclose(dbase *q)
+{
+ if ((q->handle->sync)(q->handle,0))
+ return -1;
+
+#ifdef DB_VERSION_MAJOR
+ if ( (q->cursor->c_close(q->cursor)) ||
+ ((q->handle->close)(q->handle, 0)) )
+#else
+ if ((q->handle->close)(q->handle))
+#endif
+ return -1;
+ return 0;
+}
+
+void
+free_dbs(
+ dbase * q
+ )
+{
+ if ((q->handle) && (_dbclose(q)))
+ dbms_log(L_ERROR,"Sync/Close(%s) returned an error during closing of db", q->name);
+
+#ifdef STATIC_BUFF
+ if (free_dbase_list_len < free_dbase_list_keep) {
+ q->nxt = free_dbase_list;
+ free_dbase_list = q;
+ free_dbase_list_len ++;
+ } else
+#endif
+ myfree(q);
+
+#ifndef STATIC_BUFF
+ if (q->pfile) myfree(q->pfile);
+ if (q->name) myfree(q->name);
+#endif
+ dbase_counter --;
+};
+
+void
+zap_dbs (
+ dbase * r
+ )
+{
+ dbase * * p;
+ connection * s;
+
+ /* XXX we do not want this ?! before we
+ * know it we end up in n**2 land
+ */
+ for ( p = &first_dbp; *p && *p != r; )
+ p = &((*p)->nxt);
+
+ if ( *p == NULL) {
+ dbms_log(L_ERROR,"DBase to zap not found");
+ return;
+ };
+
+ /* should we not first check all the connections
+ * to see if there are (about to) close..
+ */
+ for(s=client_list; s;s=s->next)
+ if (s->dbp == r) {
+ s->close = 1; MX;
+ };
+ *p = r->nxt;
+ free_dbs(r);
+ }
+
+
+void close_all_dbps() {
+ dbase * p;
+
+ for(p=first_dbp; p;) {
+ dbase * q;
+ q = p; p=p->nxt;
+ free_dbs( q ); /* XXXX why am I not just calling ZAP ? */
+ };
+ first_dbp=NULL;
+ }
+
+/* opening of a local database..
+ */
+int open_dbp( dbase * p ) {
+
+#if 0
+ HASHINFO priv = {
+ 16*1024, /* bsize; hash bucked size */
+ 8, /* ffactor, # keys/bucket */
+ 3000, /* nelements, guestimate */
+ 512*1024, /* cache size */
+ NULL, /* hash function */
+ 0 /* use current host order */
+ };
+#endif
+
+#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1 or 2 */
+#ifdef DB_VERSION_MAJOR
+ DB_INFO btreeinfo;
+ memset(&btreeinfo, 0, sizeof(btreeinfo));
+ btreeinfo.bt_compare = ( p->bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? rdfstore_backend_dbms_compare_int : ( p->bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? rdfstore_backend_dbms_compare_double : NULL ;
+#else
+ BTREEINFO btreeinfo;
+ memset(&btreeinfo, 0, sizeof(btreeinfo));
+ btreeinfo.compare = ( p->bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ? rdfstore_backend_dbms_compare_int : ( p->bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ? rdfstore_backend_dbms_compare_double : NULL ;
+#endif
+#endif
+
+ umask(0);
+
+ /* XXX Do note that we _have_ a mode variable. We just ignore it.
+ * except for the create flag.
+ *
+ * XXX we could also pass a &priv=NULL pointer to let the DB's work this
+ * one out..
+ */
+
+#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1 or 2 */
+
+#ifdef DB_VERSION_MAJOR
+ if ( (db_open( p->pfile,
+ DB_BTREE,
+ DB_CREATE, /* only create it should be ((ro==0) ? ( DB_CREATE ) : ( DB_RDONLY ) ) */
+ 0666, NULL, &btreeinfo, &p->handle )) ||
+#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 6
+ ((p->handle->cursor)(p->handle, NULL, &p->cursor))
+#else
+ ((p->handle->cursor)(p->handle, NULL, &p->cursor, 0))
+#endif
+ ) {
+#else
+
+#if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2
+ if (!(p->handle = (DB *)__db185_open( p->pfile,
+ p->mode,
+ 0666, DB_BTREE, &btreeinfo ))) {
+#else
+ if (!(p->handle = (DB *)dbopen( p->pfile,
+ p->mode,
+ 0666, DB_BTREE, &btreeinfo ))) {
+#endif /* DB_LIBRARY_COMPATIBILITY_API */
+
+#endif
+
+#else /* Berkeley DB Version > 2 */
+ if (db_create(&p->handle, NULL,0))
+ return errno;
+
+ /* set the b-tree comparinson function to the one passed */
+ if( p->bt_compare_fcn_type != NULL ) {
+ p->handle->set_bt_compare(p->handle, ( p->bt_compare_fcn_type == FLAT_STORE_BT_COMP_INT ) ?
+ rdfstore_backend_dbms_compare_int : ( p->bt_compare_fcn_type == FLAT_STORE_BT_COMP_DOUBLE ) ?
+ rdfstore_backend_dbms_compare_double : NULL );
+ };
+
+ p->handle->set_errfile(p->handle,stderr);
+ p->handle->set_errpfx(p->handle,"DBMS BerkelyDB");
+
+ if ( (p->handle->open( p->handle,
+#if DB_VERSION_MAJOR >= 4 && DB_VERSION_MINOR > 0 && DB_VERSION_PATCH >= 17
+ NULL,
+#endif
+ p->pfile,
+ NULL,
+ DB_BTREE,
+ DB_CREATE, /* only create it should be ((ro==0) ? ( DB_CREATE ) : ( DB_RDONLY ) ) */
+ 0666 )) ||
+ ((p->handle->cursor)(p->handle, NULL, &p->cursor, 0)) ) {
+#endif /* Berkeley DB Version > 2 */
+
+ return errno;
+ };
+
+#ifndef BERKELEY_DB_1_OR_2 /* Berkeley DB Version > 2 */
+/*
+ (void)p->handle->set_h_ffactor(p->handle, 1024);
+ (void)p->handle->set_h_nelem(p->handle, (u_int32_t)6000);
+*/
+#endif
+
+ return 0;
+ }
+
+
+dbase * get_dbp (connection *r, dbms_xsmode_t xsmode, int bt_compare_fcn_type, DBT * v2 ) {
+ dbase * p;
+ char * pfile;
+ char name[ 255 ], *n, *m;
+ int i;
+ int mode = 0;
+ tops mops = T_NONE;
+
+ /* Clean up the name */
+ bzero(name,sizeof(name));
+ for(m = (unsigned char *)(v2->data),n=name,i=0;i<v2->size && i<sizeof(name)-1;i++)
+ if (isalnum((int)(m[i]))) *n++ = m[i];
+ *n='\0';
+
+ r->op = allowed_ops_on_dbase(r->address.sin_addr.s_addr, name);
+ dbms_log(L_DEBUG,"Permissions for %s/%s - %s",
+ name, inet_ntoa(r->address.sin_addr),op2string(r->op));
+
+ switch(xsmode) {
+ case DBMS_XSMODE_RDONLY:
+ mops = T_RDONLY;
+ mode = O_RDONLY;
+ break;
+ ;;
+ case DBMS_XSMODE_RDWR:
+ mops = T_RDWR;
+ mode = O_RDWR;
+ break;
+ ;;
+ case DBMS_XSMODE_CREAT:
+ mops = T_CREAT;
+ mode = O_RDWR | O_CREAT;
+ break;
+ ;;
+ case DBMS_XSMODE_DROP:
+ mops = T_DROP;
+ mode = O_RDWR | O_CREAT;
+ break;
+ default:
+ dbms_log(L_ERROR,"Impossible XSmode(bug) %d requed on %s",
+ xsmode,name);
+ return NULL;
+ break;
+ }
+
+ if (mops > r->op) {
+ char * ip = strdup(inet_ntoa(r->address.sin_addr));
+ dbms_log(L_ERROR,"Access violation on %s: %s requested %s - but may up to %s",
+ name, ip, op2string(mops),op2string(r->op));
+ free(ip);
+ return NULL;
+ };
+
+ /* Max allowed operation */
+ r->op = MIN(mops,r->op);
+ dbms_log(L_DEBUG,"Permissions for %s/%s - asked %s - granted %s",
+ name, inet_ntoa(r->address.sin_addr),op2string(mops),
+ op2string(r->op));
+
+#if 0
+ /* We always add a RDWR to the open - as it may be the case
+ * that some later connection needs RW. XXX fixme.
+ */
+ mode = ( mode & (~ O_RDONLY)) | O_RDWR;
+#endif
+
+#ifndef RDFSTORE_PLATFORM_SOLARIS
+#ifndef RDFSTORE_PLATFORM_LINUX
+ /* Try to get an exclusive lock if possible */
+ mode |= O_EXLOCK;
+#endif
+#endif
+
+ for ( p = first_dbp; p; p=p->nxt)
+ if (strcmp(p->name,name)==0) {
+ int oldmode = p->mode;
+
+ /* If the database has the b-tree comparinson function we need - simply
+ * return it. If we are forking - and this is not the process
+ * really handling the database - then ignore all this. Otherwise we
+ * fail with an error
+ */
+ if ((((p->bt_compare_fcn_type) & bt_compare_fcn_type) == bt_compare_fcn_type )
+#ifdef FORKING
+ || (!mum_pid)
+#endif
+ ) {
+ return p;
+ } else {
+ dbms_log(L_ERROR, "Wrong b-tree comparinson function %d on %s - it should be %d",
+ bt_compare_fcn_type, p->name, p->bt_compare_fcn_type );
+ return NULL;
+ };
+
+ /* If the database already has the perm's we need - simply
+ * return it. If we are forking - and this is not the process
+ * really handling the database - then ignore all this
+ */
+ if ((((p->mode) & mode) == mode )
+#ifdef FORKING
+ || (!mum_pid)
+#endif
+ ) return p;
+
+ /* we need to (re)open the database with the higher level perm's we
+ * we need this time..
+ */
+ p->mode = mode;
+ if (_dbclose(p) || open_dbp( p )) {
+ dbms_log(L_ERROR,
+ "DBase %s could not be be reopened with the right permissions %d",
+ p->name,p->mode);
+ /* try to reopen the dbase with the old permissions
+ * (for the other connections still active)
+ */
+ p->mode = oldmode;
+
+ /* bail out - but not clean up de *p; as other
+ * connections are still using it.
+ */
+ if (open_dbp(p))
+ return NULL;
+
+ /* give up - and have the DB removed (even for
+ * the other connections ! */
+ goto err_and_exit;
+ }
+ return p;
+ }
+
+ if (dbase_counter > HARD_MAX_DBASE) {
+ dbms_log(L_ERROR,"Hard max number of dabases hit. (bug?)");
+ return NULL;
+ };
+
+#ifdef STATIC_BUFF
+ if (free_dbase_list)
+ {
+ p = free_dbase_list;
+ free_dbase_list = free_dbase_list->nxt;
+ } else {
+ if (free_dbase_list_keep < free_dbase_list_max)
+ free_dbase_list_keep += 2;
+#else
+{
+#endif
+ p = mymalloc(sizeof(dbase));
+ }
+
+ if (p == NULL) {
+ dbms_log(L_ERROR,"No Memory (for another dbase 1)");
+ return NULL;
+ };
+ bzero(p,sizeof(dbase));
+ p->nxt = first_dbp;
+ first_dbp = p;
+ dbase_counter ++;
+
+#ifndef STATIC_BUFF
+ p->name = NULL;
+ p->pfile = NULL;
+#else
+ p->name[0] ='\0';
+ p->pfile[0] = '\0';
+#endif
+ p->num_cls = 0;
+ p->close = 0;
+ p->mode = mode;
+ p->bt_compare_fcn_type = bt_compare_fcn_type;
+ p->sname = v2->size;
+ p->handle = NULL;
+
+#ifdef FORKING
+ p->handled_by = NULL;
+#endif
+
+#ifdef STATIC_BUFF
+ if ( 1+ v2->size > MAX_STATIC_NAME )
+#else
+ if ((p->name = mymalloc( 1+v2->size ))==NULL)
+#endif
+ {
+ dbms_log(L_ERROR,"No Memory (for another dbase 2)");
+ goto clean_and_exit;
+ };
+
+ strcpy(p->name, name);
+
+ if (!(pfile= mkpath(my_dir,p->name)))
+ goto clean_and_exit;
+
+#ifdef STATIC_BUFF
+ if ( strlen(pfile)+1 > MAX_STATIC_PFILE )
+#else
+ if ((p->pfile = mymalloc(strlen(pfile)+1)) == NULL )
+#endif
+ {
+ dbms_log(L_ERROR,"No Memory (for another dbase 3)");
+ goto clean_and_exit;
+ };
+ strcpy(p->pfile,pfile);
+
+ /* Check if the DB exists unless we are on an allowed
+ * create operations level.
+ */
+ if (r->op < T_CREAT) {
+ struct stat sb;
+ int s=stat(p->pfile,&sb);
+ if (s==-1) {
+ dbms_log(L_ERROR,"DB %s not found\n",p->pfile);
+ goto clean_and_exit;
+ }
+ /* DB exists - we are good. */
+ };
+
+#ifdef FORKING
+ /* if we are the main process, then pass
+ * on the request to a suitable child;
+ * if we are the 'child' then do the
+ * actual work..
+ */
+ if (!mum_pid) {
+ int mdbs=0,c=0;
+ struct child_rec * q, *best;
+
+ /* count # of processes and get the least
+ * loaded one of the lot. Or create a
+ * fresh one. XXXX We could also go for
+ * a rotational approach, modulo the counter.
+ * that would remove the need to loop, but
+ * spoil the load distribution.
+ */
+ if (child_counter < max_processes) {
+ q=create_new_child();
+ /* fork/child or error */
+ if ((q == NULL) && (errno))
+ goto clean_and_exit;
+ if (q == NULL)
+ return NULL; /* just bail out if we are the child */
+ best=q;
+ }
+ else {
+ for(c=0,q=children; q; q=q->nxt)
+ if ( mdbs == 0 || q->num_dbs < mdbs ) {
+ mdbs = q->num_dbs;
+ best = q;
+ };
+ };
+
+ p->handled_by = best;
+ p->handled_by->num_dbs ++;
+
+ return p;
+ }; /* if mother */
+ /* we are a child... just open normal.
+ */
+#endif
+ if (open_dbp( p ) == 0)
+ return p;
+
+err_and_exit:
+ dbms_log(L_ERROR,"open_dbp(1) %s(mode %d) (bt_compare %d) failed: %s",p->pfile,p->mode,p->bt_compare_fcn_type, strerror(errno));
+
+clean_and_exit:
+ p->close = 1; MX;
+
+ /* repair... and shuffle... */
+ first_dbp = p->nxt;
+#ifndef STATIC_BUFF
+ if (p->pfile) myfree(p->pfile);
+ if (p->name) myfree(p->name);
+ if (p) myfree(p);
+#else
+ p->nxt = free_dbase_list;
+ free_dbase_list = p;
+#endif
+ dbase_counter --;
+ return NULL;
+}
+
+void do_init( connection * r) {
+ DBT val;
+ u_long proto;
+ dbms_xsmode_t xsmode;
+ int bt_compare_fcn_type;
+
+ memset(&val, 0, sizeof(val));
+
+ val.data = &proto;
+ val.size = sizeof( u_long );
+
+ xsmode = (dbms_xsmode_t)((u_long) ntohl( ((u_long *)(r->v1.data))[1] ));
+
+#ifdef FORKING
+ assert(mum_pid==0);
+#endif
+ if (r->v1.size == 0) {
+ reply_log(r,L_ERROR,"No protocol version");
+ return;
+ };
+
+ proto =((u_long *)(r->v1.data))[0];
+ if ( ntohl(proto) != DBMS_PROTO ) {
+ reply_log(r,L_ERROR,"Protocol not supported");
+ return;
+ };
+
+ bt_compare_fcn_type = ((int) ntohl( ((u_long *)(r->v1.data))[2] ));
+ if ( ( bt_compare_fcn_type != 0 ) &&
+ ( bt_compare_fcn_type < FLAT_STORE_BT_COMP_INT ) &&
+ ( bt_compare_fcn_type > FLAT_STORE_BT_COMP_DATE ) ) {
+ reply_log(r,L_ERROR,"B-tree sorting function not supported");
+ return;
+ };
+
+ /* work out wether we have this dbase already open,
+ * and open it if ness.
+ */
+ r->dbp = get_dbp( r, xsmode, bt_compare_fcn_type, &(r->v2)); /* returns NULL on error or if it is a child */
+
+ if (r->dbp == NULL) {
+ if (errno == ENOENT) {
+ dbms_log(L_DEBUG,"Closing instantly with a not found");
+ dispatch(r, TOKEN_INIT | F_NOTFOUND,&val,NULL);
+ return;
+ };
+#ifdef FORKING
+ if (!mum_pid)
+#endif
+ reply_log(r,L_ERROR,"Open2 database '%s' failed: %s",
+ iprt(&(r->v2)),strerror(errno));
+ return;
+ };
+
+ r->dbp->num_cls ++;
+#ifdef FORKING
+{
+ /* We -also- need to record some xtra things which are lost acrss the connection. */
+ u_long extra[4];
+ extra[0] = ((u_long *)(r->v1.data))[0]; /* proto */
+ extra[1] = ((u_long *)(r->v1.data))[1]; /* mode */
+ extra[2] = ((u_long *)(r->v1.data))[2]; /* bt_compare_fcn_type */
+ extra[3] = r->address.sin_addr.s_addr;
+ r->v1.data = extra;
+ r->v1.size = sizeof(extra);
+ if (handoff_fd(r->dbp->handled_by, r))
+ reply_log(r,L_ERROR,"handoff %s : %s",
+ r->dbp->name,strerror(errno));
+}
+#else
+ dispatch(r, TOKEN_INIT | F_FOUND,&val,NULL);
+#endif
+ return;
+ }
+
+#ifdef FORKING
+void do_pass( connection * mums_r) {
+ /* this is not really a RQ coming in from a child.. bit instead
+ * a warning that we are about to pass a file descriptor
+ * in the next message. There is no need to actually confirm
+ * anything if we are successfull, we should just be on the
+ * standby to get the FD, and treat it as a new connection..
+ *
+ * note that the r->fd is _not_ a client fd, but the one to
+ * our mother.
+ */
+ connection * r;
+ int newfd;
+ u_long proto;
+ dbms_xsmode_t xsmode;
+ DBT val;
+ u_long bt_compare_fcn_type;
+
+ memset(&val, 0, sizeof(val));
+ assert(mums_r->v1.size = 4*sizeof(u_long));
+ mums_r->address.sin_addr.s_addr = ((u_long *)(mums_r->v1.data))[3];
+
+ assert(mum_pid);
+
+ if ((newfd=takeon_fd(mum->clientfd))<0) {
+ reply_log(mums_r,L_ERROR,"Take on failed: %s",
+ strerror(errno));
+ /* give up on the connection to mum ?*/
+ mums_r->close = 1; MX;
+ return;
+ };
+
+ /* try to take this FD on board.. and let it do
+ * whatever error moaning itself.
+ */
+ proto =((u_long *)(mums_r->v1.data))[0];
+ xsmode = (dbms_xsmode_t)((u_long) htonl(((u_long *)(mums_r->v1.data))[1]));
+
+ dbms_log(L_INFORM,"PASS db='%s' mode %d",iprt(&(mums_r->v2)),xsmode);
+
+ if ((r = handle_new_connection( newfd, C_CLIENT, mums_r->address)) == NULL)
+ return;
+
+ /* is this the sort of init data we can handle ?
+ */
+ if ( ntohl(proto) != DBMS_PROTO ) {
+ reply_log(r,L_ERROR,"Protocol not supported");
+ return;
+ };
+
+ bt_compare_fcn_type = ((int) ntohl( ((u_long *)(mums_r->v1.data))[2] ));
+ if ( ( bt_compare_fcn_type != 0 ) &&
+ ( ( bt_compare_fcn_type < FLAT_STORE_BT_COMP_INT ) ||
+ ( bt_compare_fcn_type > FLAT_STORE_BT_COMP_DATE ) ) ) {
+ reply_log(r,L_ERROR,"B-tree sorting function not supported");
+ return;
+ };
+
+ r->dbp = get_dbp( r, xsmode, bt_compare_fcn_type, &(mums_r->v2));
+
+ if (r->dbp== NULL) {
+ if (errno == ENOENT) {
+ dispatch(r, TOKEN_INIT | F_NOTFOUND,&val,NULL);
+ r->close = 1; MX;
+ return;
+ };
+ reply_log(r,L_ERROR,"Open database %s failed: %s",
+ iprt(&(mums_r->v2)),strerror(errno));
+ return;
+ };
+
+ r->dbp->num_cls ++;
+ r->dbp->handled_by = NULL;
+
+ /* let the _real_ client know all is well. */
+ proto=htonl(DBMS_PROTO);
+ val.data= &proto;
+ val.size = sizeof( u_long );
+
+ dispatch(r, TOKEN_INIT | F_FOUND,&val,NULL);
+
+ dbms_log(L_INFORM,"PASS send init repy on %d to client",r->clientfd);
+ return;
+ };
+#endif
+
+void do_fetch( connection * r) {
+ DBT key, val;
+ int err;
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command FETCH");
+ return;
+ };
+
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->get)(r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->get)(r->dbp->handle, &key, &val, 0);
+#endif
+
+ if (err == 0)
+ dispatch(r,TOKEN_FETCH | F_FOUND,&key,&val);
+ else
+#ifdef DB_VERSION_MAJOR
+ if (err == DB_NOTFOUND)
+#else
+ if (err == 1)
+#endif
+ dispatch(r,TOKEN_FETCH | F_NOTFOUND,NULL,NULL);
+ else {
+ errno=err;
+ reply_log(r,L_ERROR,"fetch on %s failed: %s (klen=%d, vlen=%d, err=%d(1))",r->dbp->name,strerror(errno), key.size,val.size,err);
+ }
+ }
+
+void do_inc ( connection * r) {
+ DBT key, val;
+ int err;
+ unsigned long l;
+ char * p;
+ char outbuf[256]; /* surely shorter than UMAX_LONG */
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command FETCH");
+ return;
+ };
+
+ /* all we get from the client is the key, and
+ * all we return is the (increased) value
+ */
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->get)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->get)( r->dbp->handle, &key, &val,0);
+#endif
+
+#ifdef DB_VERSION_MAJOR
+ if ((err == DB_NOTFOUND) || (val.size == 0)) {
+#else
+ if ((err == 1) || (val.size == 0)) {
+#endif
+ dispatch(r,TOKEN_INC | F_NOTFOUND,NULL,NULL);
+ return;
+ }
+ else
+ if (err) {
+#ifdef DB_VERSION_MAJOR
+ errno=err;
+#endif
+ reply_log(r,L_ERROR,"inc on %s failed: %s",r->dbp->name,
+ strerror(errno) );
+ return;
+ };
+
+ /* XXX bit of a hack; but perl seems to deal with
+ * all storage as ascii strings in some un-
+ * specified locale.
+ */
+ bzero(outbuf,256);
+ strncpy(outbuf,val.data,MIN( val.size, 255 ));
+ l=strtoul( outbuf, &p, 10 );
+
+ if (*p || l == ULONG_MAX || errno == ERANGE) {
+ reply_log(r,L_ERROR,"inc on %s failed: %s",r->dbp->name,
+ "Not the (entire) string is an unsigned integer"
+ );
+ return;
+ };
+ /* this is where it all happens... */
+ l++;
+
+ bzero(outbuf,256);
+ snprintf(outbuf,255,"%lu",l);
+ val.data = & outbuf;
+ val.size = strlen(outbuf);
+
+ /* and put it back..
+ *
+ * Put routines return -1 on error (setting errno), 0
+ * on success, and 1 if the R_NOOVERWRITE flag was set
+ * and the key already exists in the file.
+ */
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->put)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->put)( r->dbp->handle, &key, &val,0);
+#endif
+
+ /* just send it back as an ascii string
+ */
+#ifdef DB_VERSION_MAJOR
+ if (( err == 0 ) || ( err < 0 ))
+#else
+ if (( err == 0 ) || ( err == 1 ))
+#endif
+ dispatch(r,TOKEN_INC | F_FOUND,NULL,&val);
+ else {
+#ifdef DB_VERSION_MAJOR
+ errno=err;
+#endif
+ reply_log(r,L_ERROR,"inc store on %s failed: %s",
+ r->dbp->name,strerror(errno));
+ };
+ };
+
+void do_dec ( connection * r) {
+ DBT key, val;
+ int err;
+ unsigned long l;
+ char * p;
+ char outbuf[256]; /* surely shorter than UMAX_LONG */
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command FETCH");
+ return;
+ };
+
+ /* all we get from the client is the key, and
+ * all we return is the (decreased) value
+ */
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->get)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->get)( r->dbp->handle, &key, &val,0);
+#endif
+
+#ifdef DB_VERSION_MAJOR
+ if ((err == DB_NOTFOUND) || (val.size == 0)) {
+#else
+ if ((err == 1) || (val.size == 0)) {
+#endif
+ dispatch(r,TOKEN_DEC | F_NOTFOUND,NULL,NULL);
+ return;
+ }
+ else
+ if (err) {
+#ifdef DB_VERSION_MAJOR
+ errno=err;
+#endif
+ reply_log(r,L_ERROR,"dec on %s failed: %s",r->dbp->name,
+ strerror(errno) );
+ return;
+ };
+
+ /* XXX bit of a hack; but perl seems to deal with
+ * all storage as ascii strings in some un-
+ * specified locale.
+ */
+ bzero(outbuf,256);
+ strncpy(outbuf,val.data,MIN( val.size, 255 ));
+ l=strtoul( outbuf, &p, 10 );
+
+ if (*p || l == ULONG_MAX || l == 0 || errno == ERANGE) {
+ reply_log(r,L_ERROR,"dec on %s failed: %s",r->dbp->name,
+ "Not the (entire) string is an unsigned integer"
+ );
+ return;
+ };
+ /* this is where it all happens... */
+ l--;
+
+ bzero(outbuf,256);
+ snprintf(outbuf,255,"%lu",l);
+ val.data = & outbuf;
+ val.size = strlen(outbuf);
+
+ /* and put it back..
+ *
+ * Put routines return -1 on error (setting errno), 0
+ * on success, and 1 if the R_NOOVERWRITE flag was set
+ * and the key already exists in the file.
+ */
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->put)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->put)( r->dbp->handle, &key, &val,0);
+#endif
+
+ /* just send it back as an ascii string
+ */
+#ifdef DB_VERSION_MAJOR
+ if (( err == 0 ) || ( err < 0 ))
+#else
+ if (( err == 0 ) || ( err == 1 ))
+#endif
+ dispatch(r,TOKEN_DEC | F_FOUND,NULL,&val);
+ else
+#ifdef DB_VERSION_MAJOR
+ {
+ errno=err;
+ reply_log(r,L_ERROR,"dec store on %s failed: %s",
+ r->dbp->name,strerror(errno));
+ };
+#else
+ reply_log(r,L_ERROR,"dec store on %s failed: %s",
+ r->dbp->name,strerror(errno));
+#endif
+ };
+
+/* atomic packed increment */
+void do_packinc ( connection * r) {
+ DBT key, val;
+ int err;
+ dbms_counter l=0;
+ unsigned char outbuf[256];
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command FETCH");
+ return;
+ };
+
+ /* all we get from the client is the key, and
+ * all we return is the (increased) value
+ */
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->get)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->get)( r->dbp->handle, &key, &val,0);
+#endif
+
+#ifdef DB_VERSION_MAJOR
+ if ((err == DB_NOTFOUND) || (val.size == 0)) {
+#else
+ if ((err == 1) || (val.size == 0)) {
+#endif
+ dispatch(r,TOKEN_PACKINC | F_NOTFOUND,NULL,NULL);
+ return;
+ }
+ else
+ if (err) {
+#ifdef DB_VERSION_MAJOR
+ errno=err;
+#endif
+ reply_log(r,L_ERROR,"packinc on %s failed: %s",r->dbp->name,
+ strerror(errno) );
+ return;
+ };
+
+ l = ntohl(*(dbms_counter *)val.data);
+
+ /* this is where it all happens... */
+ l++;
+
+ val.data = outbuf;
+ val.size = sizeof(dbms_counter);
+
+ *(dbms_counter *)val.data = htonl(l);
+
+ /* and put it back..
+ *
+ * Put routines return -1 on error (setting errno), 0
+ * on success, and 1 if the R_NOOVERWRITE flag was set
+ * and the key already exists in the file.
+ */
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->put)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->put)( r->dbp->handle, &key, &val,0);
+#endif
+
+ /* just send it back as an ascii string
+ */
+#ifdef DB_VERSION_MAJOR
+ if (( err == 0 ) || ( err < 0 ))
+#else
+ if (( err == 0 ) || ( err == 1 ))
+#endif
+ dispatch(r,TOKEN_PACKINC | F_FOUND,NULL,&val);
+ else
+#ifdef DB_VERSION_MAJOR
+ {
+ errno=err;
+ reply_log(r,L_ERROR,"packinc store on %s failed: %s",
+ r->dbp->name,strerror(errno));
+ };
+#else
+ reply_log(r,L_ERROR,"packinc store on %s failed: %s",
+ r->dbp->name,strerror(errno));
+#endif
+ };
+
+/* atomic packed decrement */
+void do_packdec ( connection * r) {
+ DBT key, val;
+ int err;
+ dbms_counter l=0;
+ unsigned char outbuf[256]; /* surely shorter than UMAX_LONG */
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command FETCH");
+ return;
+ };
+
+ /* all we get from the client is the key, and
+ * all we return is the (increased) value
+ */
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->get)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->get)( r->dbp->handle, &key, &val,0);
+#endif
+
+#ifdef DB_VERSION_MAJOR
+ if ((err == DB_NOTFOUND) || (val.size == 0)) {
+#else
+ if ((err == 1) || (val.size == 0)) {
+#endif
+ dispatch(r,TOKEN_PACKDEC | F_NOTFOUND,NULL,NULL);
+ return;
+ }
+ else
+ if (err) {
+#ifdef DB_VERSION_MAJOR
+ errno=err;
+#endif
+ reply_log(r,L_ERROR,"packdec on %s failed: %s",r->dbp->name,
+ strerror(errno) );
+ return;
+ };
+
+ l = ntohl(*(dbms_counter *)val.data);
+ /* this is where it all happens... */
+ l--;
+
+
+ val.data = outbuf;
+ val.size = sizeof(uint32_t)+1;
+
+ *(dbms_counter *)val.data = htonl(l);
+
+ /* and put it back..
+ *
+ * Put routines return -1 on error (setting errno), 0
+ * on success, and 1 if the R_NOOVERWRITE flag was set
+ * and the key already exists in the file.
+ */
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->put)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->put)( r->dbp->handle, &key, &val,0);
+#endif
+
+ /* just send it back as an ascii string
+ */
+#ifdef DB_VERSION_MAJOR
+ if (( err == 0 ) || ( err < 0 ))
+#else
+ if (( err == 0 ) || ( err == 1 ))
+#endif
+ dispatch(r,TOKEN_PACKDEC | F_FOUND,NULL,&val);
+ else
+#ifdef DB_VERSION_MAJOR
+ {
+ errno=err;
+ reply_log(r,L_ERROR,"packdec store on %s failed: %s",
+ r->dbp->name,strerror(errno));
+ };
+#else
+ reply_log(r,L_ERROR,"packdec store on %s failed: %s",
+ r->dbp->name,strerror(errno));
+#endif
+ };
+
+void do_exists( connection * r) {
+ DBT key, val;
+ int err;
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command EXISTS");
+ return;
+ };
+
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->get)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->get)( r->dbp->handle, &key, &val,0);
+#endif
+
+ if ( err == 0 )
+ dispatch(r,TOKEN_EXISTS | F_FOUND,NULL,NULL);
+ else
+#ifdef DB_VERSION_MAJOR
+ if (err == DB_NOTFOUND)
+ dispatch(r,TOKEN_EXISTS | F_NOTFOUND,NULL,NULL);
+ else {
+ errno=err;
+ reply_log(r,L_ERROR,"exists on %s failed: %s",r->dbp->name,strerror(errno));
+ }
+#else
+ if (err == 1)
+ dispatch(r,TOKEN_EXISTS | F_NOTFOUND,NULL,NULL);
+ else
+ reply_log(r,L_ERROR,"exists on %s failed: %s",r->dbp->name,strerror(errno));
+#endif
+ };
+
+void do_delete( connection * r) {
+ DBT key;
+ int err;
+
+ memset(&key, 0, sizeof(key));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command DELETE");
+ return;
+ };
+
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->del)( r->dbp->handle, NULL, &key, 0);
+#else
+ err=(r->dbp->handle->del)( r->dbp->handle, &key,0);
+#endif
+
+ if ( err == 0 )
+ dispatch(r,TOKEN_DELETE | F_FOUND,NULL,NULL);
+ else
+#ifdef DB_VERSION_MAJOR
+ if (err == DB_NOTFOUND)
+ dispatch(r,TOKEN_DELETE | F_NOTFOUND,NULL,NULL);
+ else {
+ errno=err;
+ reply_log(r,L_ERROR,"delete on %s failed: %s",r->dbp->name,strerror(errno));
+ }
+#else
+ if ( err == 1 )
+ dispatch(r,TOKEN_DELETE | F_NOTFOUND,NULL,NULL);
+ else
+ reply_log(r,L_ERROR,"delete on %s failed: %s",r->dbp->name,strerror(errno));
+#endif
+ };
+
+void do_store( connection * r) {
+ DBT key, val;
+ int err;
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command STORE");
+ return;
+ };
+
+ key.data = r->v1.data;
+ key.size = r->v1.size;
+
+ val.data = r->v2.data;
+ val.size = r->v2.size;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->handle->put)( r->dbp->handle, NULL, &key, &val, 0);
+#else
+ err=(r->dbp->handle->put)( r->dbp->handle, &key, &val,0);
+#endif
+
+ if ( err == 0 )
+ dispatch(r,TOKEN_STORE | F_FOUND,NULL,NULL); /* it was F_NOTFOUND wich was returning always 1 even if not there (F_NOTFOUND) */
+ else
+#ifdef DB_VERSION_MAJOR
+ if ( err < 0 )
+ dispatch(r,TOKEN_STORE | F_FOUND,NULL,NULL);
+ else {
+ errno=err;
+ reply_log(r,L_ERROR,"store on %s failed: %s",r->dbp->name,strerror(errno));
+ };
+#else
+ if ( err == 1 )
+ dispatch(r,TOKEN_STORE | F_NOTFOUND,NULL,NULL); /* it was F_FOUND which was returning always 0 even if already there (F_FOUND) see above dispatch */
+ else
+ reply_log(r,L_ERROR,"store on %s failed: %s",r->dbp->name,strerror(errno));
+#endif
+
+ };
+
+void do_sync( connection * r) {
+ int err=0;
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command SYNC");
+ return;
+ };
+
+ err=(r->dbp->handle->sync)( r->dbp->handle,0);
+
+ if (err != 0 ) {
+ reply_log(r,L_ERROR,"sync on %s failed: %s",r->dbp->name,strerror(errno));
+ }
+ else {
+ dispatch(r,TOKEN_SYNC,NULL,NULL);
+ };
+ };
+
+void do_clear( connection * r) {
+ int err;
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command CLEAR");
+ return;
+ };
+
+ /* close the database, remove the file, and repoen... ? */
+ if ( (_dbclose(r->dbp)) ||
+ ((err=unlink(r->dbp->pfile)) !=0) ||
+ ((err=open_dbp( r->dbp )) != 0) )
+ {
+ reply_log(r,L_ERROR,"clear on %s failed: %s",r->dbp->name,strerror(errno));
+ return;
+ };
+
+ trace("%6s %12s %s","SYNC",r->dbp->name,eptr(err));
+ dispatch(r, TOKEN_CLEAR,NULL, NULL);
+ };
+
+void do_list( connection * r) {
+#if 0
+ DBT key, val;
+ int err;
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ /* now the issue here is... do we want to do
+ * the entire array; as one HUGE malloc ?
+ */
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command LIST");
+ return;
+ };
+
+ /* keep track of whom used the cursor last...*/
+ r->dbp->lastfd = r->clientfd;
+
+ f = R_FIRST;
+ for(;;) {
+ err=(r->dbp->handle->seq)( r->dbp->handle, &key, &val,f);
+ if ( err ) last;
+ f = F_NEXT;
+
+ };
+
+ if ( err < 0 )
+ reply_log(r,L_ERROR,"first on %s failed: %s",
+ r->dbp->name,strerror(errno));
+ else
+ if ( err == 1 )
+ dispatch(r,TOKEN_FIRSTKEY | F_NOTFOUND,NULL,NULL);
+ else
+ dispatch(r,TOKEN_LIST | F_FOUND,&key,&val);
+#endif
+ reply_log(r,L_ERROR,"Not implemented.. yet");
+ }
+
+void do_ping( connection * r) {
+ dispatch(r,TOKEN_PING | F_FOUND,NULL,NULL);
+ }
+
+void do_drop( connection * r) {
+ char dbpath[ 1024 ];
+ dbms_log(L_INFORM,"Drop cmd");
+
+ /* Construct name - add .db where/if needed ?? */
+ /* snprintf(dbpath,sizeof(dbpath),"%s.db",r->dbp->pfile); */
+ snprintf(dbpath,sizeof(dbpath),"%s",r->dbp->pfile);
+
+ /* or r->dbp->close = 2; */
+ zap_dbs(r->dbp);
+
+ if (unlink(dbpath))
+ reply_log(r,L_ERROR,
+ "DB file %s could not be deleted: %s",
+ dbpath,strerror(errno));
+ else
+ dispatch(r,TOKEN_DROP| F_FOUND,NULL,NULL);
+}
+
+void do_close( connection * r) {
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command CLOSE");
+ return;
+ };
+
+ dispatch(r,TOKEN_CLOSE,NULL,NULL);
+ r->close = 1; MX;
+ }
+
+/* Combined from function; from first record when flag==R_FIRST or DB_FIRST
+ * or from the current cursor if flag=R_CURSOR or DB_SET_RANGE. If
+ * no cursos is yet set; the latter two default to an R_FIRST or DB_FIRST.
+ */
+static
+void _from( connection * r, DBT *key, DBT *val, int flag) {
+ int err;
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command FIRST/FROM");
+ return;
+ };
+
+ /* keep track of whom used the cursor last...*/
+ r->dbp->lastfd = r->clientfd;
+
+#ifdef DB_VERSION_MAJOR
+ err=(r->dbp->cursor->c_get)( r->dbp->cursor, key, val, flag);
+#else
+ err=(r->dbp->handle->seq)( r->dbp->handle, key, val,flag);
+#endif
+
+#if DB_VERSION_MAJOR >= 2
+ if (err == DB_NOTFOUND)
+ dispatch(r,( (flag==DB_FIRST) ? TOKEN_FIRSTKEY : TOKEN_FROM ) | F_NOTFOUND,NULL,NULL);
+ else
+ if ( err == 0 )
+ dispatch(r,( (flag==DB_FIRST) ? TOKEN_FIRSTKEY : TOKEN_FROM ) | F_FOUND,key,val);
+ else {
+ errno=err;
+ reply_log(r,L_ERROR,"first on %s failed: %s",r->dbp->name,strerror(errno));
+ }
+#else
+ if ( err == 1 )
+ dispatch(r,( (flag==R_FIRST) ? TOKEN_FIRSTKEY : TOKEN_FROM ) | F_NOTFOUND,NULL,NULL);
+ else
+ if ( err == 0 )
+ dispatch(r,( (flag==R_FIRST) ? TOKEN_FIRSTKEY : TOKEN_FROM ) | F_FOUND,key,val);
+ else
+ reply_log(r,L_ERROR,"first on %s failed: %s",r->dbp->name,strerror(errno));
+#endif
+};
+
+void do_first(connection * r) {
+ DBT key, val;
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+#if DB_VERSION_MAJOR >= 2
+ _from(r,&key,&val,DB_FIRST);
+#else
+ _from(r,&key,&val,R_FIRST);
+#endif
+}
+
+void do_from(connection *r) {
+ DBT key, val;
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ key.data = r->v1.data; /* copy the requested closest key */
+ key.size = r->v1.size;
+
+#if DB_VERSION_MAJOR >= 2
+ _from(r,&key,&val,DB_SET_RANGE);
+#else
+ _from(r,&key,&val,R_CURSOR);
+#endif
+};
+
+
+void do_next( connection * r) {
+ DBT key, val;
+ int err;
+
+ memset(&key, 0, sizeof(key));
+ memset(&val, 0, sizeof(val));
+
+ if (r->type != C_CLIENT) {
+ dbms_log(L_ERROR,"Command received from non-client command NEXT");
+ return;
+ };
+
+ /* We need to set the cursor first, if we where
+ * not the last using it.
+ */
+ if ( r->dbp->lastfd != r->clientfd ) {
+ r->dbp->lastfd = r->clientfd;
+ key.data = r->v1.data; /* copy the previous key if any */
+ key.size = r->v1.size;
+
+#if DB_VERSION_MAJOR >= 2
+ err=(r->dbp->cursor->c_get)(r->dbp->cursor, &key, &val, DB_NEXT);
+#else
+ err=(r->dbp->handle->seq)( r->dbp->handle, &key, &val, R_NEXT);
+#endif
+
+#ifdef DB_VERSION_MAJOR
+ if ( (err != 0) && (err != DB_NOTFOUND) ) {
+ reply_log(r,L_ERROR,"Internal DB Error %s",r->dbp->name);
+ return;
+ };
+#else
+ if (err<0 && errno ==0)
+ dbms_log(L_WARN,"seq-cursor We have the impossible err=%d and %d",
+ err,errno);
+
+ if ((err != 0) && (err != 1) && (errno != 0) ) {
+ reply_log(r,L_ERROR,"Internal DB Error %s",r->dbp->name);
+ return;
+ };
+#endif
+
+ /* BUG: we could detect the fact that the previous key
+ * the callee was aware of, has been zapped. For
+ * now we note that, if the key is not there, we
+ * have received the next greater key. Which we
+ * thus return ?! This is an issue.
+ */
+ }
+ else
+ err = 0;
+
+ if (err == 0)
+#if DB_VERSION_MAJOR >= 2
+ err=(r->dbp->cursor->c_get)(r->dbp->cursor, &key, &val, DB_NEXT);
+#else
+ err=(r->dbp->handle->seq)( r->dbp->handle, &key, &val, R_NEXT);
+#endif
+
+ trace("%6s %12s %20s: %s %s","NEXT",
+ r->dbp->name, iprt(&key),
+ iprt( err==0 ? &val : NULL ),eptr(err));
+
+#ifdef DB_VERSION_MAJOR
+ if ( ( err == DB_NOTFOUND ) || ( err > 0 ) )
+ dispatch(r,TOKEN_NEXTKEY | F_NOTFOUND,NULL,NULL);
+ else
+#else
+ if (( err == 1 ) || (( err <0 ) && (errno == 0)) )
+ dispatch(r,TOKEN_NEXTKEY | F_NOTFOUND,NULL,NULL);
+ else
+#endif
+ if ( err == 0 )
+ dispatch(r,TOKEN_NEXTKEY | F_FOUND,&key,&val);
+ else {
+#ifdef DB_VERSION_MAJOR
+ errno=err;
+#endif
+ reply_log(r,L_ERROR,"next on %s failed: %s",r->dbp->name,strerror(errno));
+ };
+ };
+
+struct command_req cmd_table[ TOKEN_MAX ];
+#define IT(i,s,f,o) { cmd_table[i].cnt = 0; cmd_table[i].cmd = i; cmd_table[i].info = s; cmd_table[i].handler = f; cmd_table[i].op = o; }
+void init_cmd_table( void )
+{
+ int i;
+ for(i=0;i<TOKEN_MAX;i++)
+ IT( i, "VOID",NULL, T_NONE );
+
+ IT( TOKEN_INIT, "INIT",&do_init, T_ERR); /* chicken/egg - we do not know the error yet */
+ IT( TOKEN_FETCH, "FTCH",&do_fetch, T_RDONLY);
+ IT( TOKEN_STORE, "STRE",&do_store, T_RDWR);
+ IT( TOKEN_DELETE, "DELE",&do_delete, T_RDWR);
+ IT( TOKEN_CLOSE, "CLSE",&do_close, T_NONE);
+ IT( TOKEN_NEXTKEY, "NEXT",&do_next, T_RDONLY);
+ IT( TOKEN_FIRSTKEY, "FRST",&do_first, T_RDONLY);
+ IT( TOKEN_EXISTS, "EXST",&do_exists, T_RDONLY);
+ IT( TOKEN_SYNC, "SYNC",&do_sync, T_RDWR);
+ IT( TOKEN_CLEAR, "CLRS",&do_clear, T_CREAT);
+ IT( TOKEN_PING, "PING",&do_ping, T_NONE);
+ IT( TOKEN_DROP, "DROP",&do_drop, T_DROP);
+ IT( TOKEN_INC, "INCR",&do_inc, T_RDWR);
+ IT( TOKEN_DEC, "DECR",&do_dec, T_RDWR);
+ IT( TOKEN_PACKINC, "PINC",&do_packinc, T_RDWR);
+ IT( TOKEN_PACKDEC, "PDEC",&do_packdec, T_RDWR);
+ IT( TOKEN_LIST, "LIST",&do_list, T_RDONLY);
+ IT( TOKEN_FROM, "FROM",&do_from, T_RDONLY);
+#ifdef FORKING
+ IT( TOKEN_FDPASS,"PASS",&do_pass, T_ERR);
+#endif
+}
+
+void parse_request( connection * r) {
+ register int i = r->cmd.token;
+
+ if ( i>=0 && i<= TOKEN_MAX && cmd_table[i].handler) {
+ if (cmd_table[i].op <= r->op) {
+ cmd_table[i].cnt++;
+ (cmd_table[i].handler)(r);
+ } else {
+ char * ip = strdup(inet_ntoa(r->address.sin_addr));
+ reply_log(r,L_ERROR,"Access violation for %s on %s (required is %s but IP is limited to %s)",
+ ip,cmd_table[i].info,
+ op2string(cmd_table[i].op),op2string(r->op));
+ free(ip);
+ r->close = 1; MX;
+ }
+ return;
+ }
+
+ reply_log(r,L_ERROR,"Unkown command token %d",i);
+ r->close = 1; MX;
+ return;
+}
+
+/* misc subroutines (copied from ../../backend_bdb_store.c - should be merged) */
+
+/*
+ * The following compare function are used for btree(s) for basic
+ * XML-Schema data types xsd:integer, xsd:double (and will xsd:date)
+ *
+ * They return:
+ * < 0 if a < b
+ * = 0 if a = b
+ * > 0 if a > b
+ */
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_dbms_compare_int(
+ const DBT *a,
+ const DBT *b ) {
+#else
+static int rdfstore_backend_dbms_compare_int(
+ DB *file,
+ const DBT *a,
+ const DBT *b ) {
+#endif
+ long ai, bi;
+
+ memcpy(&ai, a->data, sizeof(long));
+ memcpy(&bi, b->data, sizeof(long));
+
+ return (ai - bi);
+ };
+
+#ifdef BERKELEY_DB_1_OR_2
+static int rdfstore_backend_dbms_compare_double(
+ const DBT *a,
+ const DBT *b ) {
+#else
+static int rdfstore_backend_dbms_compare_double(
+ DB *file,
+ const DBT *a,
+ const DBT *b ) {
+#endif
+ double ad,bd;
+
+ memcpy(&ad, a->data, sizeof(double));
+ memcpy(&bd, b->data, sizeof(double));
+
+ if ( ad < bd ) {
+ return -1;
+ } else if ( ad > bd) {
+ return 1;
+ };
+
+ return 0;
+ };
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.h
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.h?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.h (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/handler.h Fri Apr 13 01:56:01 2007
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+ * Dirk-Willem van Gulik <di...@webweaving.org>
+ *
+ * NOTICE
+ *
+ * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+ * file you should have received together with this source code. If you did not get a
+ * a copy of such a license agreement you can pick up one at:
+ *
+ * http://rdfstore.sourceforge.net/LICENSE
+ *
+ *
+ * $Id: handler.h,v 1.4 2006/06/19 10:10:22 areggiori Exp $
+ */
+
+void close_all_dbps();
+void parse_request( connection * r);
+void init_cmd_table( void );
Added: incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/loop.c
URL: http://svn.apache.org/viewvc/incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/loop.c?view=auto&rev=528394
==============================================================================
--- incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/loop.c (added)
+++ incubator/triplesoup/donations/TRIPLES-3-RDFStore/dbms/deamon/loop.c Fri Apr 13 01:56:01 2007
@@ -0,0 +1,267 @@
+/*
+ * Copyright (c) 2000-2006 Alberto Reggiori <ar...@webweaving.org>
+ * Dirk-Willem van Gulik <di...@webweaving.org>
+ *
+ * NOTICE
+ *
+ * This product is distributed under a BSD/ASF like license as described in the 'LICENSE'
+ * file you should have received together with this source code. If you did not get a
+ * a copy of such a license agreement you can pick up one at:
+ *
+ * http://rdfstore.sourceforge.net/LICENSE
+ *
+ *
+ * $Id: loop.c,v 1.18 2006/06/19 10:10:22 areggiori Exp $
+ */
+#include "dbms.h"
+#include "dbms_compat.h"
+#include "dbms_comms.h"
+#include "dbmsd.h"
+
+#include "deamon.h"
+#include "handler.h"
+
+/* for debugging..
+ */
+char *
+show(
+ int max,
+ fd_set * all,
+ fd_set * show
+ )
+{ int i;
+ static char out[16*1024];
+ out[0]='\0';
+ for(i=0; i<max; i++) if (FD_ISSET(i,all)) {
+ char tmp[16];
+ if (FD_ISSET(i,show))
+ snprintf(tmp,16," %4d",i);
+ else
+ snprintf(tmp,16," ");
+ strcat(out,tmp);
+ };
+ return out;
+}
+
+/* sync and flush on DB level, file descriptior level
+ * as well as on filesystem/kernel level.
+ */
+void flush_all( void ) {
+ dbase * p;
+ int one = 0;
+ int fd;
+
+ for(p=first_dbp; p;p=p->nxt)
+ if (p->handle) {
+ (p->handle->sync)(p->handle,0);
+#ifdef DB_VERSION_MAJOR
+ (p->handle->fd)(p->handle, &fd);
+#else
+ fd = (p->handle->fd)(p->handle);
+#endif
+ fsync( fd );
+ one++;
+ };
+
+ if (one)
+ sync();
+
+ dbms_log(L_INFORM,"Synced %d databases and the file system",one);
+ }
+
+void
+select_loop( void )
+{
+ time_t lsync = time(NULL);
+ /* seconds and micro seconds. */
+ struct timeval nill={600,0};
+ struct timeval *np = &nill;
+
+ if (!mum_pid)
+ np = NULL;
+
+ for (;;) {
+ int n;
+ time_t now = time(NULL);
+ struct connection *r, *s;
+ dbase * p;
+#ifdef FORKING
+ child_rec * d;
+#endif
+ rset=allrset;
+ wset=allwset;
+ eset=alleset;
+
+ /* mothers do not time out, or if
+ * the last cycle was synced and
+ * was nothing to do...
+ */
+ if ((n=select(maxfd+1,&rset,&wset,&eset,np)) < 0) {
+ if (errno != EINTR )
+ dbms_log(L_ERROR,"RWE Select Probem %s",strerror(errno));
+ continue;
+ };
+
+ /* not done anything for 15 minutes or so.
+ * are there any connections outstanding apart
+ * from the one to mum ?
+ */
+ if ( (n==0) && (mum_pid) &&
+ (!(first_dbp && client_list && client_list->next))) {
+
+ // clients but no dbase ?
+ assert( ! (client_list) && (client_list->next));
+
+ // a dbase but no clients ?
+ assert(! first_dbp);
+
+ dbms_log(L_INFORM,"Nothing to do, this child stops..");
+
+ exit(0);
+ }
+
+ /* upon request from alberto... flush
+ every 5 minutes or so.. see if that
+ cures the issue since we moved to raid.
+ */
+ if ((mum_pid) && (difftime(now,lsync) > 300)) {
+ flush_all();
+ lsync = now;
+ /* next round, we can wait for just about forever */
+ // if (n == 0) np = NULL; XXX not needed
+ };
+ dbms_log(L_DEBUG,"Read : %s",show(maxfd+1,&allrset,&rset));
+ dbms_log(L_DEBUG,"Write : %s",show(maxfd+1,&allrset,&wset));
+ dbms_log(L_DEBUG,"Except: %s",show(maxfd+1,&allrset,&eset));
+
+ /* Is someone knocking on our front door ?
+ */
+ if ((sockfd>=0) && (FD_ISSET(sockfd,&rset))) {
+ struct sockaddr_in client;
+ int len=sizeof(client);
+ int fd;
+
+ if (mum_pid)
+ dbms_log(L_ERROR,"Should not get such an accept()");
+ else
+ if ((fd = accept(sockfd,
+ ( struct sockaddr *) &client, &len)) <0)
+ dbms_log(L_ERROR,"Could not accept");
+ else {
+ tops level = allowed_ops(client.sin_addr.s_addr);
+ dbms_log(L_DEBUG,"Accept(%d) op level for IP=%s: %s",
+ fd,inet_ntoa(client.sin_addr),op2string(level));
+
+ if (level > T_NONE)
+ handle_new_connection(fd, C_NEW_CLIENT, client);
+ else {
+ dbms_log(L_ERROR,"Accept violation: %s rejected.",
+ inet_ntoa(client.sin_addr));
+ close(fd);
+ }
+ }
+ }
+
+ /* note that for the pthreads we rely on a mark-and-sweep
+ * style of garbage collect.
+ */
+ if (client_list != NULL) for ( s = client_list; s != NULL; ) {
+ /* Page early, as the record might get zapped
+ * and taken out of the lists in this loop.
+ */
+ assert( s != NULL );
+ r=s; s=r->next;
+
+ assert( r != s );
+ if (r->close)
+ continue;
+
+ if (FD_ISSET(r->clientfd,&rset)) {
+ int trapit=getpid(); // trap forks.
+ if (r->tosend != 0) {
+ dbms_log(L_ERROR,"read request received while working on send");
+ zap(r);
+ continue;
+ }
+ dbms_log(L_DEBUG,"read F=%d R%d W%d E%d",
+ r->clientfd,
+ FD_ISSET(r->clientfd,&rset) ? 1 : 0,
+ FD_ISSET(r->clientfd,&wset) ? 1 : 0,
+ FD_ISSET(r->clientfd,&eset) ? 1 : 0
+ );
+
+ if (r->toget == 0)
+ initial_read(r);
+ else
+ continue_read(r);
+
+ if (trapit != getpid())
+ break;
+#ifdef TIMEOUT
+ r->last=time(NULL);
+#endif
+ if (r->close)
+ continue;
+ };
+
+ if (FD_ISSET(r->clientfd,&wset)) {
+ if (r->tosend >= 0 )
+ continue_send(r);
+ else
+ dbms_log(L_ERROR,"write select while not expecting to write");
+#ifdef TIMEOUT
+ r->last=time(NULL);
+#endif
+ if (r->close)
+ continue;
+ };
+
+// XXX this eset is a pointless
+// excersize, perhaps ??
+// only seen on linux-RH5.1
+//
+ if (FD_ISSET(r->clientfd,&eset)) {
+ dbms_log(L_ERROR,"Some exception. Unexpected");
+ r->close = 1; MX;
+#ifdef TIMEOUT
+ r->last=time(NULL);
+#endif
+ };
+#ifdef TIMEOUT
+ if (difftime( r->last, time(NULL) ) > TIMEOUT) {
+ inform("Timeout, closed the connection.");
+ r->close =1; MX;
+ };
+#endif
+ }; /* client set loop */
+
+ /* clean up operations...
+ * note the order
+ */
+ for ( s=client_list; s != NULL; ) {
+ r=s; s=r->next;
+ assert( r != s );
+ if ( r->close ) {
+ dbms_log(L_DEBUG,"General clean %d",r->clientfd);
+ zap(r);
+ };
+ };
+
+#ifdef FORKING
+ for(d=children;d;) {
+ child_rec * e = d; d=d->nxt;
+ assert( d != e );
+ if (e->close)
+ zap_child( e );
+ };
+#endif
+
+ for(p=first_dbp; p;) {
+ dbase * q=p; p=p->nxt;
+ assert( p != q );
+ if (q->close)
+ zap_dbs(q);
+ };
+
+ }; /* Forever.. */
+ } /* of main */