소스 검색

Merge commit 'cvs/head' into flatstore

* commit 'cvs/head': (25 commits)
  - a set of minimalistic config files for testing purposes
  - adding missing end of doxygen group
  - missing READMEs added
  - headers moved within the doxygen section
  - removed unneeded libs, thanks to Marcus Better <[email protected]>
  - support for flatstore uris with relative pathnames (they are
  - wrong array index fixed
  - minor bug fixes
  - new version of flatstore module for new db api in SER 2.1
  - various warning fixes
  - "strlen(flat_escape) > 1" fix
  - DB_FLOAT support
  - export param types adjusted to PARAM_STR/STRING & PARAM_INT
  - added record delimiter and escape char params
  - converted to the new management interface
  - module interface exended with list of management functions
  - documents are now valid (apart from xmlns:xi problem which would require
  - DTDs and stylesheets will be downloaded from the network if they are
  - improved documentation system
  - fixed memory leak in flat_reopen_connection, reported by
  ...
Jan Janak 16 년 전
부모
커밋
531b59fc6e

+ 10 - 0
modules/db_flatstore/Makefile

@@ -0,0 +1,10 @@
+# $Id$
+#
+# WARNING: do not run this directly, it should be run by the master Makefile
+
+include ../../Makefile.defs
+auto_gen=
+NAME=flatstore.so
+LIBS=
+
+include ../../Makefile.modules

+ 95 - 0
modules/db_flatstore/README

@@ -0,0 +1,95 @@
+1. Flatstore Module
+
+Jan Janak
+
+   FhG FOKUS
+   <[email protected]>
+
+   Copyright © 2004, 2005 FhG FOKUS
+   Revision History
+   Revision $Revision$ $Date$
+     __________________________________________________________________
+
+   1.1. Overview
+
+        1.1.1. Rotating Log Files
+
+   1.2. Parameters
+
+        1.2.1. flush (integer)
+
+1.1. Overview
+
+   Flatstore is one of so-called SER database modules. It does not export
+   any functions executable from the configuration scripts, but it exports
+   a subset of functions from the database API and thus other module can
+   use it instead of, for example, mysql module.
+
+   The module does not export all functions of the database API, it
+   supports only one function, insert. The module is limited but very
+   fast. It is especially suitable for storing accounting information on
+   sites with extremely high traffic. If MySQL is too slow or if you get a
+   huge amount of accounting data then you can consider using this module.
+   Note that the acc module is the only module that was tested with
+   flastore.
+
+   The format of the files produced by this module is plain text. Each
+   line consists of several fields, fields are separated by | character.
+   New information is always appended at the end of the file, searching,
+   deleting and updating of existing data is not supported by the module.
+
+   The acc module can be configured to use flatstore module as database
+   backend using the db_url_parameter:
+modparam("acc", "db_url", "flatstore:/var/log/acc")
+
+   This configuration options tells acc module that it should use the
+   flatstore module and the flatstore module should create all files in
+   /var/log/acc directory. The directory must exist and SER processes must
+   have permissions to create files in that directory.
+
+   Name of files in that directory will follow the following pattern:
+<table_name>_<process_name>.log
+
+   For example, entries writen by SER process 8 into acc table would be
+   written in file acc_8.log. For each table there will be several files,
+   one file for every SER process that wrote some data into that table.
+   The main reason why there are several files for each table is that it
+   is much faster to have one file per process, because it does not
+   require any locking and thus SER processes will not block each other.
+   To get the complete data for a table you can simply concatenate the
+   contents of files with the same table name but different process id.
+
+1.1.1. Rotating Log Files
+
+   There is a new SER FIFO interface command called flat_rotate. When SER
+   receives the command then it will close and reopen all files used by
+   flatstore module. The rotation itself has to be done by another
+   application (such as logrotate). Follow these steps to rotate files
+   generated by flatstore module:
+     * Rename the files that you want to rotate:
+cd /var/log/acc
+mv acc_1.log acc_1.log.20050605
+mv acc_2.log acc_2.log.20050605
+mv acc_4.log acc_3.log.20050605
+...
+       Note that at this point SER will still be writing all data into the
+       renamed files.
+     * Send SER the fifo command to close and reopen the renamed files:
+serctl fifo flat_rotate
+       This will force SER to close the renamed files and open new ones
+       with original names, such as acc_1.log. New files will be open at
+       the point when SER has some data to write. It is normal that the
+       files will be not created immediately if there is no traffic on the
+       proxy server.
+     * Move the renamed files somewhere else and process them.
+
+1.2. Parameters
+
+   Revision History
+   Revision $Revision$ $Date$
+
+1.2.1. flush (integer)
+
+   Enable or disable flushing after each write.
+
+   Default value is 1.

+ 29 - 0
modules/db_flatstore/doc/Makefile

@@ -0,0 +1,29 @@
+#
+# The list of documents to build (without extensions)
+#
+DOCUMENTS = flatstore
+
+#
+# The root directory containing Makefile.doc
+#
+ROOT_DIR=../../..
+
+#
+# Validate docbook documents before generating output
+# (may be slow)
+#
+#VALIDATE=1
+
+#
+# You can override the stylesheet used to generate
+# xhtml documents here
+#
+#XHTML_XSL=$(ROOT_DIR)/doc/stylesheets/xhtml.xsl
+
+#
+# You can override the stylesheet used to generate
+# plain text documents here
+#
+#TXT_XSL=$(XHTML_XSL)
+
+include $(ROOT_DIR)/Makefile.doc

+ 134 - 0
modules/db_flatstore/doc/flatstore.xml

@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="flatstore" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<authorgroup>
+	    <author>
+		<firstname>Jan</firstname>
+		<surname>Janak</surname>
+		<affiliation><orgname>FhG FOKUS</orgname></affiliation>
+		<email>[email protected]</email>
+	    </author>
+	</authorgroup>
+	<copyright>
+	    <year>2004</year>
+	    <year>2005</year>
+	    <holder>FhG FOKUS</holder>
+	</copyright>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Flatstore Module</title>
+
+    <section id="flatstore.overview">
+	<title>Overview</title>
+	<para>
+	    Flatstore is one of so-called SER database modules. It does not
+	    export any functions executable from the configuration scripts, but
+	    it exports a subset of functions from the database API and thus
+	    other module can use it instead of, for example, mysql module.
+	</para>
+	<para>
+	    The module does not export all functions of the database API, it
+	    supports only one function, insert. The module is limited but very
+	    fast. It is especially suitable for storing accounting information
+	    on sites with extremely high traffic. If MySQL is too slow or if
+	    you get a huge amount of accounting data then you can consider
+	    using this module. Note that the acc module is the only module that
+	    was tested with flastore.
+	</para>
+	<para>
+	    The format of the files produced by this module is plain text. Each
+	    line consists of several fields, fields are separated by |
+	    character. New information is always appended at the end of the
+	    file, searching, deleting and updating of existing data is not
+	    supported by the module.
+	</para>
+	<para>
+	    The acc module can be configured to use flatstore module as
+	    database backend using the db_url_parameter:
+	</para>
+	<programlisting>
+modparam("acc", "db_url", "flatstore:/var/log/acc")
+	</programlisting>
+	<para>
+	    This configuration options tells acc module that it should use the
+	    flatstore module and the flatstore module should create all files
+	    in /var/log/acc directory. The directory must exist and SER
+	    processes must have permissions to create files in that directory.
+	</para>
+	<para>
+	    Name of files in that directory will follow the following pattern:
+	</para>
+	<programlisting>
+&lt;table_name&gt;_&lt;process_name&gt;.log
+	</programlisting>
+	<para>
+	    For example, entries writen by SER process 8 into acc table would
+	    be written in file acc_8.log. For each table there will be several
+	    files, one file for every SER process that wrote some data into
+	    that table. The main reason why there are several files for each
+	    table is that it is much faster to have one file per process,
+	    because it does not require any locking and thus SER processes will
+	    not block each other. To get the complete data for a table you can
+	    simply concatenate the contents of files with the same table name
+	    but different process id.
+	</para>
+	<section id="rotating">
+	    <title>Rotating Log Files</title>
+	    <para>
+		There is a new SER FIFO interface command called flat_rotate.
+		When SER receives the command then it will close and reopen all
+		files used by flatstore module. The rotation itself has to be
+		done by another application (such as logrotate). Follow these
+		steps to rotate files generated by flatstore module:
+	    </para>
+	    <itemizedlist>
+		<listitem>
+		    <para>
+			Rename the files that you want to rotate:
+			<screen>
+cd /var/log/acc
+mv acc_1.log acc_1.log.20050605
+mv acc_2.log acc_2.log.20050605
+mv acc_4.log acc_3.log.20050605
+...
+			</screen>
+			Note that at this point SER will still be writing all
+			data into the renamed files.
+		    </para>
+		</listitem>
+		<listitem>
+		    <para>
+			Send SER the fifo command to close and reopen the
+			renamed files:
+			<screen>
+serctl fifo flat_rotate
+			</screen>
+			This will force SER to close the renamed files and open
+			new ones with original names, such as
+			<filename>acc_1.log</filename>. New files will be open
+			at the point when SER has some data to write. It is
+			normal that the files will be not created immediately
+			if there is no traffic on the proxy server.
+		    </para>
+		</listitem>
+		<listitem>
+		    <para>
+			Move the renamed files somewhere else and process them.
+		    </para>
+		</listitem>
+	    </itemizedlist>
+	</section>
+    </section>
+
+    <xi:include href="params.xml"/>
+
+</section>

+ 17 - 0
modules/db_flatstore/doc/functions.xml

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="flatstore.functions" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Functions</title>
+
+</section>

+ 26 - 0
modules/db_flatstore/doc/params.xml

@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" 
+   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
+
+<section id="flatstore.functions" xmlns:xi="http://www.w3.org/2001/XInclude">
+    <sectioninfo>
+	<revhistory>
+	    <revision>
+		<revnumber>$Revision$</revnumber>
+		<date>$Date$</date>
+	    </revision>
+	</revhistory>
+    </sectioninfo>
+
+    <title>Parameters</title>
+
+    <section id="flush">
+	<title><varname>flush</varname> (integer)</title>
+	<para>
+	    Enable or disable flushing after each write.
+	</para>
+	<para>
+	    Default value is 1.
+	</para>
+    </section>
+</section>

+ 216 - 0
modules/db_flatstore/flat_cmd.c

@@ -0,0 +1,216 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG FOKUS
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * Inmplementation of flatstore commands.
+ */
+
+#include "flat_cmd.h"
+#include "flat_con.h"
+#include "flatstore_mod.h"
+
+#include "../../mem/mem.h"
+
+#include <string.h>
+#include <errno.h>
+
+
+/** Destroys a flat_cmd structure.
+ * This function frees all memory used by flat_cmd structure.
+ * @param cmd A pointer to generic db_cmd command being freed.
+ * @param payload A pointer to flat_cmd structure to be freed.
+ */
+static void flat_cmd_free(db_cmd_t* cmd, struct flat_cmd* payload)
+{
+	db_drv_free(&payload->gen);
+	pkg_free(payload);
+}
+
+
+int flat_cmd(db_cmd_t* cmd)
+{
+	struct flat_cmd* fcmd;
+	db_con_t* con;
+
+	if (cmd->type != DB_PUT) {
+		ERR("flatstore: The driver supports PUT operation only.\n");
+		return -1;
+	}
+
+	if (DB_FLD_EMPTY(cmd->vals)) {
+		ERR("flatstore: PUT command with no values encountered\n");
+		return -1;
+	}
+
+	fcmd = (struct flat_cmd*)pkg_malloc(sizeof(struct flat_cmd));
+	if (fcmd == NULL) {
+		ERR("flatstore: No memory left\n");
+		return -1;
+	}
+	memset(fcmd, '\0', sizeof(struct flat_cmd));
+	if (db_drv_init(&fcmd->gen, flat_cmd_free) < 0) goto error;
+
+	/* FIXME */
+	con = cmd->ctx->con[db_payload_idx];
+	if (flat_open_table(&fcmd->file_index, con, &cmd->table) < 0) goto error;
+
+	DB_SET_PAYLOAD(cmd, fcmd);
+	return 0;
+
+ error:
+	if (fcmd) {
+		DB_SET_PAYLOAD(cmd, NULL);
+		db_drv_free(&fcmd->gen);
+		pkg_free(fcmd);
+	}
+	return -1;
+}
+
+
+int flat_put(db_res_t* res, db_cmd_t* cmd)
+{
+	struct flat_cmd* fcmd;
+	struct flat_con* fcon;
+	db_con_t* con;
+	int i;
+	FILE* f;
+	char delims[4], *s;
+	size_t len;
+
+	fcmd = DB_GET_PAYLOAD(cmd);
+	/* FIXME */
+	con = cmd->ctx->con[db_payload_idx];
+	fcon = DB_GET_PAYLOAD(con);
+
+	f = fcon->file[fcmd->file_index].f;
+	if (f == NULL) {
+		ERR("flatstore: Cannot write, file handle not open\n");
+		return -1;
+	}
+
+	if (flat_local_timestamp < *flat_rotate) {
+		flat_con_disconnect(con);
+		if (flat_con_connect(con) < 0) {
+			ERR("flatstore: Error while rotating files\n");
+			return -1;
+		}
+		flat_local_timestamp = *flat_rotate;
+	}
+
+	for(i = 0; !DB_FLD_EMPTY(cmd->vals) && !DB_FLD_LAST(cmd->vals[i]); i++) {
+		if (i) {
+			if (fprintf(f, "%c", flat_delimiter.s[0]) < 0) goto error;
+		}
+
+		/* TODO: how to distinguish NULL from empty */
+		if (cmd->vals[i].flags & DB_NULL) continue;
+		
+		switch(cmd->vals[i].type) {
+		case DB_INT:
+			if (fprintf(f, "%d", cmd->vals[i].v.int4) < 0) goto error;
+			break;
+
+		case DB_FLOAT:
+			if (fprintf(f, "%f", cmd->vals[i].v.flt) < 0) goto error;
+			break;
+
+		case DB_DOUBLE:
+			if (fprintf(f, "%f", cmd->vals[i].v.dbl) < 0) goto error;
+			break;
+
+		case DB_DATETIME:
+			if (fprintf(f, "%u", (unsigned int)cmd->vals[i].v.time) < 0) 
+				goto error;
+			break;
+
+		case DB_CSTR:
+			s = cmd->vals[i].v.cstr;
+			delims[0] = flat_delimiter.s[0];
+			delims[1] = flat_record_delimiter.s[0];
+			delims[2] = flat_escape.s[0];
+			delims[3] = '\0';
+			while (*s) {
+				len = strcspn(s, delims);
+				if (fprintf(f, "%.*s", (int)len, s) < 0) goto error;
+				s += len;
+				if (*s) {
+					/* FIXME: do not use the escaped value for easier parsing */
+					if (fprintf(f, "%c%c", flat_escape.s[0], *s) < 0) goto error;
+					s++;
+				}
+			}
+			break;
+
+		case DB_STR:
+		case DB_BLOB:
+			/* FIXME: rewrite */
+			s = cmd->vals[i].v.lstr.s;
+			len = cmd->vals[i].v.lstr.len;
+			while (len > 0) {
+				char *c;
+				for (c = s; len > 0 && 
+						 *c != flat_delimiter.s[0] && 
+						 *c != flat_record_delimiter.s[0] && 
+						 *c != flat_escape.s[0]; 
+					 c++, len--);
+				if (fprintf(f, "%.*s", (int)(c-s), s) < 0) goto error;
+				s = c;
+				if (len > 0) {
+					if (fprintf(f, "%c%c", flat_escape.s[0], *s) < 0) goto error;
+					s++;
+					len--;
+				}
+			}
+			break;
+
+		case DB_BITMAP:
+			if (fprintf(f, "%u", cmd->vals[i].v.bitmap) < 0) goto error;
+			break;
+
+		default:
+			BUG("flatstore: Unsupported field type %d\n", cmd->vals[i].type);
+			return -1;
+		}
+	}
+
+	if (fprintf(f, "%c", flat_record_delimiter.s[0]) < 0) goto error;
+
+	if (flat_flush && (fflush(f) != 0)) {
+		ERR("flatstore: Error while flushing file: %s\n", strerror(errno));
+		return -1;
+	}
+
+	return 0;
+
+ error:
+	ERR("flastore: Error while writing data to file\n");
+	return -1;
+}
+
+
+/** @} */

+ 75 - 0
modules/db_flatstore/flat_cmd.h

@@ -0,0 +1,75 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG FOKUS
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FLAT_CMD_H
+#define _FLAT_CMD_H
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * Inmplementation of flatstore commands.
+ */
+
+#include "../../db/db_drv.h"
+#include "../../db/db_cmd.h"
+
+
+/** Extension structure of db_cmd adding flatstore specific data.
+ * This data structure extends the generic data structure db_cmd in the
+ * database API with data specific to the flatstore driver.
+ */
+struct flat_cmd {
+	db_drv_t gen; /**< Generic part of the data structure (must be first) */
+	int file_index;
+};
+
+
+/** Creates a new flat_cmd data structure.
+ * This function allocates and initializes memory for a new flat_cmd data
+ * structure. The data structure is then attached to the generic db_cmd
+ * structure in cmd parameter.
+ * @param cmd A generic db_cmd structure to which the newly created flat_cmd
+ *            structure will be attached.
+ */
+int flat_cmd(db_cmd_t* cmd);
+
+
+/** The main execution function in flat SER driver.
+ * This is the main execution function in this driver. It is executed whenever
+ * a SER module calls db_exec and the target database of the commands is
+ * flatstore.
+ * @param res A pointer to (optional) result structure if the command returns
+ *            a result.
+ * @retval 0 if executed successfully
+ * @retval A negative number if the database server failed to execute command
+ * @retval A positive number if there was an error on client side (SER)
+ */
+int flat_put(db_res_t* res, db_cmd_t* cmd);
+
+
+/** @} */
+
+#endif /* _FLAT_CMD_H */

+ 299 - 0
modules/db_flatstore/flat_con.c

@@ -0,0 +1,299 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG FOKUS
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * Inmplementation of flatstore "connections".
+ */
+
+#include "flat_con.h"
+#include "flatstore_mod.h"
+#include "flat_uri.h"
+
+#include "../../mem/mem.h"
+#include "../../dprint.h"
+#include "../../ut.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+
+/** Free all memory allocated for a flat_con structure.
+ * This function function frees all memory that is in use by
+ * a flat_con structure.
+ * @param con A generic db_con connection structure.
+ * @param payload Flatstore specific payload to be freed.
+ */
+static void flat_con_free(db_con_t* con, struct flat_con* payload)
+{
+	int i;
+	if (!payload) return;
+
+	/* delete the structure only if there are no more references
+	 * to it in the connection pool
+	 */
+	if (db_pool_remove((db_pool_entry_t*)payload) == 0) return;
+	
+	db_pool_entry_free(&payload->gen);
+
+	if (payload->file) {
+		for(i = 0; i < payload->n; i++) {
+			if (payload->file[i].filename) pkg_free(payload->file[i].filename);
+			if (payload->file[i].table.s) pkg_free(payload->file[i].table.s);
+			if (payload->file[i].f) fclose(payload->file[i].f);
+		}
+		pkg_free(payload->file);
+	}
+	pkg_free(payload);
+}
+
+
+int flat_con(db_con_t* con)
+{
+	struct flat_con* fcon;
+
+	/* First try to lookup the connection in the connection pool and
+	 * re-use it if a match is found
+	 */
+	fcon = (struct flat_con*)db_pool_get(con->uri);
+	if (fcon) {
+		DBG("flatstore: A handle to %.*s found in the connection pool\n",
+			STR_FMT(&con->uri->body));
+		goto found;
+	}
+
+	fcon = (struct flat_con*)pkg_malloc(sizeof(struct flat_con));
+	if (fcon == NULL) {
+		ERR("flatstore: No memory left\n");
+		goto error;
+	}
+	memset(fcon, '\0', sizeof(struct flat_con));
+	if (db_pool_entry_init(&fcon->gen, flat_con_free, con->uri) < 0) goto error;
+
+	DBG("flastore: Preparing new file handles to files in %.*s\n", 
+		STR_FMT(&con->uri->body));
+	
+	/* Put the newly created flatstore connection into the pool */
+	db_pool_put((struct db_pool_entry*)fcon);
+	DBG("flatstore: Handle stored in connection pool\n");
+
+ found:
+	/* Attach driver payload to the db_con structure and set connect and
+	 * disconnect functions
+	 */
+	DB_SET_PAYLOAD(con, fcon);
+	con->connect = flat_con_connect;
+	con->disconnect = flat_con_disconnect;
+	return 0;
+
+ error:
+	if (fcon) {
+		db_pool_entry_free(&fcon->gen);
+		pkg_free(fcon);
+	}
+	return -1;
+}
+
+
+int flat_con_connect(db_con_t* con)
+{
+	struct flat_con* fcon;
+	int i;
+	
+	fcon = DB_GET_PAYLOAD(con);
+	
+	/* Do not reconnect already connected connections */
+	if (fcon->flags & FLAT_OPENED) return 0;
+
+	DBG("flatstore: Opening handles to files in '%.*s'\n", 
+		STR_FMT(&con->uri->body));
+
+	/* FIXME: Make sure the directory exists, is accessible,
+	 * and we can create files there
+	 */
+
+	DBG("flatstore: Directory '%.*s' opened successfully\n", 
+		STR_FMT(&con->uri->body));
+
+	for(i = 0; i < fcon->n; i++) {
+		if (fcon->file[i].f) {
+			fclose(fcon->file[i].f);
+		}
+		fcon->file[i].f = fopen(fcon->file[i].filename, "a");
+		if (fcon->file[i].f == NULL) {
+			ERR("flatstore: Error while opening file handle to '%s': %s\n", 
+				fcon->file[i].filename, strerror(errno));
+			return -1;
+		}
+	}
+
+	fcon->flags |= FLAT_OPENED;
+	return 0;
+
+}
+
+
+void flat_con_disconnect(db_con_t* con)
+{
+	struct flat_con* fcon;
+	int i;
+
+	fcon = DB_GET_PAYLOAD(con);
+
+	if ((fcon->flags & FLAT_OPENED) == 0) return;
+
+	DBG("flatstore: Closing handles to files in '%.*s'\n", 
+		STR_FMT(&con->uri->body));
+
+	for(i = 0; i < fcon->n; i++) {
+		if (fcon->file[i].f == NULL) continue;
+		fclose(fcon->file[i].f);
+		fcon->file[i].f = NULL;
+	}
+
+	fcon->flags &= ~FLAT_OPENED;
+}
+
+
+/* returns a pkg_malloc'ed file name */
+static char* get_filename(str* dir, str* name)
+{
+    char* buf, *p;
+    int buf_len, total_len;
+
+    buf_len = pathmax();
+
+    total_len = dir->len + 1 /* / */ + 
+		name->len + 1 /* _ */+
+		flat_pid.len +
+		flat_suffix.len + 1 /* \0 */;
+
+    if (buf_len < total_len) {
+        ERR("flatstore: The path is too long (%d and PATHMAX is %d)\n",
+            total_len, buf_len);
+        return 0;
+    }
+
+    if ((buf = pkg_malloc(buf_len)) == NULL) {
+        ERR("flatstore: No memory left\n");
+        return 0;
+    }
+    p = buf;
+
+    memcpy(p, dir->s, dir->len);
+    p += dir->len;
+
+    *p++ = '/';
+
+    memcpy(p, name->s, name->len);
+    p += name->len;
+
+    *p++ = '_';
+
+    memcpy(p, flat_pid.s, flat_pid.len);
+    p += flat_pid.len;
+
+    memcpy(p, flat_suffix.s, flat_suffix.len);
+    p += flat_suffix.len;
+
+    *p = '\0';
+    return buf;
+}
+
+
+
+int flat_open_table(int* idx, db_con_t* con, str* name)
+{
+	struct flat_uri* furi;
+	struct flat_con* fcon;
+	struct flat_file* new;
+	int i;
+	char* filename, *table;
+
+	new = NULL;
+	filename = NULL;
+	table = NULL;
+	fcon = DB_GET_PAYLOAD(con);
+	furi = DB_GET_PAYLOAD(con->uri);
+	
+	for(i = 0; i < fcon->n; i++) {
+		if (name->len == fcon->file[i].table.len &&
+			!strncmp(name->s, fcon->file[i].table.s, name->len))
+			break;
+	}
+	if (fcon->n == i) {
+		/* Perform operations that can fail first (before resizing
+		 * fcon->file, so that we can fail gracefully if one of the
+		 * operations fail. 
+		 */
+		if ((filename = get_filename(&furi->path, name)) == NULL)
+			goto no_mem;
+
+		if ((table = pkg_malloc(name->len)) == NULL) goto no_mem;
+		memcpy(table, name->s, name->len);
+
+		new = pkg_realloc(fcon->file, sizeof(struct flat_file) * (fcon->n + 1));
+		if (new == NULL) goto no_mem;
+
+		fcon->file = new;
+		new = new + fcon->n; /* Advance to the new (last) element */
+		fcon->n++;
+
+		new->table.s = table;
+		new->table.len = name->len;
+		new->filename = filename;
+
+		/* Also open the file if we are connected already */
+		if (fcon->flags & FLAT_OPENED) {
+			if ((new->f = fopen(new->filename, "a")) == NULL) {
+				ERR("flatstore: Error while opening file handle to '%s': %s\n", 
+					new->filename, strerror(errno));
+				return -1;
+			}			
+		} else {
+			new->f = NULL;
+		}
+		
+		*idx = fcon->n - 1;
+	} else {
+		*idx = i;
+	}
+	DBG("flatstore: Handle to file '%s' opened successfully\n", 
+		fcon->file[*idx].filename);
+	return 0;
+
+ no_mem:
+	ERR("flatstore: No memory left\n");
+	if (filename) pkg_free(filename);
+	if (table) pkg_free(table);
+	return -1;
+}
+
+
+/** @} */

+ 93 - 0
modules/db_flatstore/flat_con.h

@@ -0,0 +1,93 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG FOKUS
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FLAT_CON_H
+#define _FLAT_CON_H
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * Inmplementation of flatstore "connections".
+ */
+
+#include "../../db/db_pool.h"
+#include "../../db/db_con.h"
+#include "../../db/db_uri.h"
+
+#include <stdio.h>
+
+
+/** 
+ * Per-connection flags for flatstore connections.
+ */
+enum flat_con_flags {
+	FLAT_OPENED      = (1 << 0), /**< Handle opened successfully */
+};
+
+
+struct flat_file {
+	char* filename; /**< Name of file within the directory */
+	str table;      /**< Table name the file belongs to */
+	FILE* f;        /**< File handle of the file */
+};
+
+
+/** A structure representing flatstore virtual connections.
+ * Flatstore module is writing data to files on a local filesystem only so
+ * there is no concept of real database connections.  In flatstore module a
+ * connection is related with a directory on the filesystem and it contains
+ * file handles to files in that directory. The file handles are then used
+ * from commands to write data in them.
+ */
+struct flat_con {
+	db_pool_entry_t gen;    /**< Generic part of the structure */
+	struct flat_file* file;
+	int n;                  /**< Size of the file array */
+	unsigned int flags;     /**< Flags */
+};
+
+
+/** Create a new flat_con structure.
+ * This function creates a new flat_con structure and attachs the structure to
+ * the generic db_con structure in the parameter.
+ * @param con A generic db_con structure to be extended with flatstore payload
+ * @retval 0 on success
+ * @retval A negative number on error
+ */
+int flat_con(db_con_t* con);
+
+
+int flat_con_connect(db_con_t* con);
+
+
+void flat_con_disconnect(db_con_t* con);
+
+
+int flat_open_table(int *idx, db_con_t* con, str* name);
+
+/** @} */
+
+#endif /* _FLAT_CON_H */

+ 61 - 0
modules/db_flatstore/flat_rpc.c

@@ -0,0 +1,61 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG FOKUS
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * Flatstore management interface
+ */
+
+#include "flat_rpc.h"
+#include "flatstore_mod.h"
+
+#include <time.h>
+
+/** Register a new file rotation request.
+ * This function can be called through the management interface in SER and it
+ * will register a new file rotation request. This function only registers the
+ * request, it will be carried out next time SER attempts to write new data
+ * into the file.
+ */
+static void rotate(rpc_t* rpc, void* c)
+{
+	*flat_rotate = time(0);
+}
+
+
+static const char* flat_rotate_doc[2] = {
+	"Close and reopen flatrotate files during log rotation.",
+	0
+};
+
+
+rpc_export_t flat_rpc[] = {
+	{"flatstore.rotate", rotate, flat_rotate_doc, 0},
+	{0, 0, 0, 0},
+};
+
+/** @} */

+ 42 - 0
modules/db_flatstore/flat_rpc.h

@@ -0,0 +1,42 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG FOKUS
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FLAT_RPC_H
+#define _FLAT_RPC_H
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * Flatstore management interface
+ */
+
+#include "../../rpc.h"
+
+extern rpc_export_t flat_rpc[];
+
+/** @} */
+
+#endif /* _FLAT_RPC_H */

+ 80 - 0
modules/db_flatstore/flat_uri.c

@@ -0,0 +1,80 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * The implementation of parser parsing flatstore:.. URIs.
+ */
+
+#include "flat_uri.h"
+
+#include "../../mem/mem.h"
+#include "../../ut.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+
+static void flat_uri_free(db_uri_t* uri, struct flat_uri* payload)
+{
+	if (payload == NULL) return;
+	if (payload->path.s) free(payload->path.s);
+	db_drv_free(&payload->drv);
+	pkg_free(payload);
+}
+
+
+int flat_uri(db_uri_t* uri)
+{
+	struct flat_uri* furi;
+
+	if ((furi = (struct flat_uri*)pkg_malloc(sizeof(*furi))) == NULL) {
+		ERR("flatstore: No memory left\n");
+		return -1;
+	}
+	memset(furi, '\0', sizeof(*furi));
+	if (db_drv_init(&furi->drv, flat_uri_free) < 0) goto error;
+
+	if ((furi->path.s = get_abs_pathname(NULL, &uri->body)) == NULL) {
+		ERR("flatstore: Error while obtaining absolute pathname for '%.*s'\n",
+			STR_FMT(&uri->body));
+		goto error;
+	}
+	furi->path.len = strlen(furi->path.s);
+
+	DB_SET_PAYLOAD(uri, furi);
+	return 0;
+
+ error:
+	if (furi) {
+		if (furi->path.s) free(furi->path.s);
+		db_drv_free(&furi->drv);
+		pkg_free(furi);
+	}
+	return -1;	
+}
+
+/** @} */

+ 62 - 0
modules/db_flatstore/flat_uri.h

@@ -0,0 +1,62 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FLAT_URI_H
+#define _FLAT_URI_H
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * The functions parsing and interpreting flatstore: URIs.
+ */
+
+#include "../../db/db_uri.h"
+#include "../../db/db_drv.h"
+
+/** Flatstore driver specific payload to attach to db_uri structures.  
+ * This is the flatstore specific structure that will be attached to generic
+ * db_uri structures in the database API in SER. The structure is used to
+ * convert relative pathnames in flatstore URIs to absolute.
+ */
+struct flat_uri {
+	db_drv_t drv;
+	/** Absolute pathname to the database directory, zero terminated */
+    str path;  
+};
+
+
+/** Create a new flat_uri structure and convert the path in parameter.
+ * This function builds a new flat_uri structure from the body of
+ * the generic URI given to it in parameter.
+ * @param uri A generic db_uri structure.
+ * @retval 0 on success
+ * @retval A negative number on error.
+ */
+int flat_uri(db_uri_t* uri);
+
+
+/** @} */
+
+#endif /* _FLAT_URI_H */

+ 205 - 0
modules/db_flatstore/flatstore_mod.c

@@ -0,0 +1,205 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG FOKUS
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/** \addtogroup flatstore
+ * @{ 
+ */
+
+/** \file 
+ * Flatstore module interface.
+ */
+
+#include "flatstore_mod.h"
+#include "flat_con.h"
+#include "flat_cmd.h"
+#include "flat_rpc.h"
+#include "flat_uri.h"
+
+#include "../../sr_module.h"
+#include "../../mem/shm_mem.h"
+#include "../../ut.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+MODULE_VERSION
+
+static int child_init(int rank);
+
+static int mod_init(void);
+
+static void mod_destroy(void);
+
+
+/** PID to be used in file names.  
+ * The flatstore module generates one file per SER process to ensure that
+ * every SER process has its own file and no locking/synchronization is
+ * necessary.  This variable contains a unique id of the SER process which
+ * will be added to the file name.
+ */
+str flat_pid = STR_NULL;
+
+
+/** Enable/disable flushing after eaach write. */
+int flat_flush = 1;
+
+
+/** Row delimiter.
+ * The character in this variable will be used to delimit rows.
+ */
+str flat_record_delimiter = STR_STATIC_INIT("\n");
+
+
+/** Field delimiter.
+ * The character in this variable will be used to delimit fields.
+ */
+str flat_delimiter = STR_STATIC_INIT("|");
+
+
+/** Escape character.
+ * The character in this variable will be used to escape specia characters,
+ * such as row and field delimiters, if they appear in the data being written
+ * in the files.
+ */
+str flat_escape = STR_STATIC_INIT("\\");
+
+
+/** Filename suffix.
+ * This is the suffix of newly created files.
+ */
+str flat_suffix = STR_STATIC_INIT(".log");
+
+
+/** Timestamp of last file rotation request.
+ * This variable holds the timestamp of the last file rotation request
+ * received through the management interface.
+ */
+time_t* flat_rotate;
+
+
+/** Timestamp of last file rotation.
+ * This variable contains the time of the last rotation of files.
+ */
+time_t flat_local_timestamp;
+
+
+/* Flatstore database module interface */
+static cmd_export_t cmds[] = {
+	{"db_uri", (cmd_function)flat_uri, 0, 0, 0},
+	{"db_con", (cmd_function)flat_con, 0, 0, 0},
+	{"db_cmd", (cmd_function)flat_cmd, 0, 0, 0},
+	{"db_put", (cmd_function)flat_put, 0, 0, 0},
+	{0, 0, 0, 0, 0}
+};
+
+
+/* Exported parameters */
+static param_export_t params[] = {
+	{"flush",            PARAM_INT, &flat_flush},
+	{"field_delimiter",  PARAM_STR, &flat_delimiter},
+	{"record_delimiter", PARAM_STR, &flat_record_delimiter},
+	{"escape_char",      PARAM_STR, &flat_escape},
+	{"file_suffix",      PARAM_STR, &flat_suffix},
+	{0, 0, 0}
+};
+
+
+struct module_exports exports = {
+	"flatstore",
+	cmds,
+	flat_rpc,    /* RPC methods */
+	params,      /*  module parameters */
+	mod_init,    /* module initialization function */
+	0,           /* response function*/
+	mod_destroy, /* destroy function */
+	0,           /* oncancel function */
+	child_init   /* per-child init function */
+};
+
+
+static int mod_init(void)
+{
+	if (flat_delimiter.len != 1) {
+		ERR("flatstore: Parameter 'field_delimiter' "
+			"must be exactly one character long.\n");
+		return -1;
+	}
+
+	if (flat_record_delimiter.len != 1) {
+		ERR("flatstore: Parameter 'record_delimiter' "
+			"must be exactly one character long.\n");
+		return -1;
+	}
+
+	if (flat_escape.len != 1) {
+		ERR("flatstore: Parameter 'escape_char' "
+			"must be exaactly one character long.\n");
+		return -1;
+	}
+
+	flat_rotate = (time_t*)shm_malloc(sizeof(time_t));
+	if (!flat_rotate) {
+		ERR("flatstore: Not enough shared memory left\n");
+		return -1;
+	}
+
+	*flat_rotate = time(0);
+	flat_local_timestamp = *flat_rotate;
+	return 0;
+}
+
+
+static void mod_destroy(void)
+{
+	if (flat_pid.s) free(flat_pid.s);
+	if (flat_rotate) shm_free(flat_rotate);
+}
+
+
+static int child_init(int rank)
+{
+	char* tmp;
+	unsigned int v;
+
+	if (rank <= 0) {
+		v = -rank;
+	} else {
+		v = rank - PROC_MIN;
+	}
+
+    if ((tmp = int2str(v, &flat_pid.len)) == NULL) {
+		BUG("flatstore: Error while converting process id to number\n");
+		return -1;
+	}
+
+	if ((flat_pid.s = strdup(tmp)) == NULL) {
+		ERR("flatstore: No memory left\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/** @} */
+

+ 51 - 0
modules/db_flatstore/flatstore_mod.h

@@ -0,0 +1,51 @@
+/*
+ * $Id$
+ *
+ * Copyright (C) 2004 FhG Fokus
+ * Copyright (C) 2008 iptelorg GmbH
+ * Written by Jan Janak <[email protected]>
+ *
+ * This file is part of SER, a free SIP server.
+ *
+ * SER is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free Software
+ * Foundation; either version 2 of the License, or (at your option) any later
+ * version.
+ *
+ * SER is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc., 
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _FLATSTORE_MOD_H
+#define _FLATSTORE_MOD_H
+
+/** @defgroup flatstore Fast plain-text write-only DB driver.
+ * @ingroup DB_API
+ */
+/** @{ */
+
+/** \file 
+ * Flatstore module interface.
+ */
+
+#include "../../str.h"
+#include <time.h>
+
+extern str     flat_pid;
+extern int     flat_flush;
+extern str     flat_record_delimiter;
+extern str     flat_delimiter;
+extern str     flat_escape;
+extern str     flat_suffix;
+extern time_t* flat_rotate;
+extern time_t  flat_local_timestamp;
+
+/** @} */
+
+#endif /* _FLATSTORE_MOD_H */

+ 22 - 0
modules/db_flatstore/ser-flatstore.cfg

@@ -0,0 +1,22 @@
+#
+# Minimalistic configuration file for SER which can be used
+# to test the flatstore SER module.
+#
+debug = 4
+fork = no
+children = 1
+log_stderror = yes
+
+loadpath "./modules"
+
+loadmodule "flatstore"
+loadmodule "sl"
+loadmodule "tm"
+loadmodule "acc_db"
+
+modparam("acc_db", "db_url", "flatstore:/tmp")
+
+route {
+	acc_db_log();
+	break;
+}

+ 2 - 0
modules/db_flatstore/todo.txt

@@ -0,0 +1,2 @@
+* Create the directory if it does not exist and check permissions
+