X-Git-Url: http://git.pk910.de/?a=blobdiff_plain;f=src%2Fsaxdb.c;h=7cd37944dad76f46228aae230c5f5956289172ce;hb=80d9ed728be4b02ac483f3339cbb184f6602d15b;hp=8de664999f4116a6907c263fffc959ba7ffded51;hpb=da8cd3de6f2144016e9eeba741a138c6ac2663a7;p=srvx.git diff --git a/src/saxdb.c b/src/saxdb.c index 8de6649..7cd3794 100644 --- a/src/saxdb.c +++ b/src/saxdb.c @@ -1,5 +1,5 @@ /* saxdb.c - srvx database manager - * Copyright 2002-2004 srvx Development Team + * Copyright 2002-2004,2007-2008 srvx Development Team * * This file is part of srvx. * @@ -24,7 +24,11 @@ #include "saxdb.h" #include "timeq.h" -DEFINE_LIST(int_list, int); +#if !defined(SAXDB_BUFFER_SIZE) +# define SAXDB_BUFFER_SIZE (32 * 1024) +#endif + +DEFINE_LIST(int_list, int) struct saxdb { char *name; @@ -33,11 +37,19 @@ struct saxdb { saxdb_reader_func_t *reader; saxdb_writer_func_t *writer; unsigned int write_interval; - time_t last_write; + unsigned long last_write; unsigned int last_write_duration; struct saxdb *prev; }; +struct saxdb_context { + struct string_buffer obuf; + FILE *output; + unsigned int indent; + struct int_list complex; + jmp_buf jbuf; +}; + #define COMPLEX(CTX) ((CTX)->complex.used ? ((CTX)->complex.list[(CTX)->complex.used-1]) : 1) static struct saxdb *last_db; @@ -58,6 +70,7 @@ saxdb_read_db(struct saxdb *db) { if (!data) return; if (db->writer == saxdb_mondo_writer) { + free_database(mondo_db); mondo_db = data; } else { db->reader(data); @@ -118,37 +131,34 @@ saxdb_register(const char *name, saxdb_reader_func_t *reader, saxdb_writer_func_ static int saxdb_write_db(struct saxdb *db) { - struct saxdb_context ctx; + struct saxdb_context *ctx; + FILE *output; char tmp_fname[MAXLEN]; int res, res2; - time_t start, finish; + unsigned long start, finish; assert(db->filename); sprintf(tmp_fname, "%s.new", db->filename); - memset(&ctx, 0, sizeof(ctx)); - ctx.output = fopen(tmp_fname, "w+"); - int_list_init(&ctx.complex); - if (!ctx.output) { + output = fopen(tmp_fname, "w+"); + if (!output) { log_module(MAIN_LOG, LOG_ERROR, "Unable to write to %s: %s", tmp_fname, strerror(errno)); - int_list_clean(&ctx.complex); return 1; } + ctx = saxdb_open_context(output); start = time(NULL); - if ((res = setjmp(ctx.jbuf)) || (res2 = db->writer(&ctx))) { + if ((res = setjmp(*saxdb_jmp_buf(ctx))) || (res2 = db->writer(ctx))) { if (res) { log_module(MAIN_LOG, LOG_ERROR, "Error writing to %s: %s", tmp_fname, strerror(res)); } else { log_module(MAIN_LOG, LOG_ERROR, "Internal error %d while writing to %s", res2, tmp_fname); } - int_list_clean(&ctx.complex); - fclose(ctx.output); + ctx->complex.used = 0; /* Squelch asserts about unbalanced output. */ + saxdb_close_context(ctx, 1); remove(tmp_fname); return 2; } finish = time(NULL); - assert(ctx.complex.used == 0); - int_list_clean(&ctx.complex); - fclose(ctx.output); + saxdb_close_context(ctx, 1); if (rename(tmp_fname, db->filename) < 0) { log_module(MAIN_LOG, LOG_ERROR, "Unable to rename %s to %s: %s", tmp_fname, db->filename, strerror(errno)); } @@ -184,46 +194,77 @@ saxdb_write_all(void) { } } -#define saxdb_put_char(DEST, CH) do { \ - if (fputc(CH, (DEST)->output) == EOF) \ - longjmp((DEST)->jbuf, errno); \ - } while (0) -#define saxdb_put_string(DEST, CH) do { \ - if (fputs(CH, (DEST)->output) == EOF) \ - longjmp((DEST)->jbuf, errno); \ - } while (0) +static void +saxdb_flush(struct saxdb_context *dest) { + ssize_t nbw; + size_t ofs; + int fd; + + assert(dest->obuf.used <= dest->obuf.size); + fd = fileno(dest->output); + for (ofs = 0; ofs < dest->obuf.used; ofs += nbw) { + nbw = write(fd, dest->obuf.list + ofs, dest->obuf.used); + if (nbw < 0) { + longjmp(dest->jbuf, errno); + } + } + dest->obuf.used = 0; +} -static inline void +static void +saxdb_put_char(struct saxdb_context *dest, char ch) { + dest->obuf.list[dest->obuf.used] = ch; + if (++dest->obuf.used == dest->obuf.size) + saxdb_flush(dest); +} + +static void saxdb_put_nchars(struct saxdb_context *dest, const char *name, int len) { - while (len--) - if (fputc(*name++, dest->output) == EOF) - longjmp(dest->jbuf, errno); + int frag; + int ofs; + + for (ofs = 0; ofs < len; ofs += frag) { + frag = dest->obuf.size - dest->obuf.used; + if (frag > len - ofs) + frag = len - ofs; + memcpy(dest->obuf.list + dest->obuf.used, name + ofs, frag); + dest->obuf.used += frag; + if (dest->obuf.used == dest->obuf.size) + saxdb_flush(dest); + } } +#define saxdb_put_string(DEST, STR) do { \ + saxdb_put_nchars((DEST), (STR), strlen(STR)); \ + } while (0) + static void saxdb_put_qstring(struct saxdb_context *dest, const char *str) { - const char *esc; + size_t ofs; + size_t span; assert(str); saxdb_put_char(dest, '"'); - while ((esc = strpbrk(str, "\\\a\b\t\n\v\f\r\""))) { - if (esc != str) - saxdb_put_nchars(dest, str, esc-str); - saxdb_put_char(dest, '\\'); - switch (*esc) { - case '\a': saxdb_put_char(dest, 'a'); break; - case '\b': saxdb_put_char(dest, 'b'); break; - case '\t': saxdb_put_char(dest, 't'); break; - case '\n': saxdb_put_char(dest, 'n'); break; - case '\v': saxdb_put_char(dest, 'v'); break; - case '\f': saxdb_put_char(dest, 'f'); break; - case '\r': saxdb_put_char(dest, 'r'); break; - case '\\': saxdb_put_char(dest, '\\'); break; - case '"': saxdb_put_char(dest, '"'); break; + for (ofs = 0; str[ofs] != '\0'; ) { + char stop; + span = strcspn(str + ofs, "\\\a\b\t\n\v\f\r\""); + saxdb_put_nchars(dest, str + ofs, span); + ofs += span; + stop = str[ofs]; + switch (stop) { + case '\0': continue; + case '\a': stop = 'a'; break; + case '\b': stop = 'b'; break; + case '\t': stop = 't'; break; + case '\n': stop = 'n'; break; + case '\v': stop = 'v'; break; + case '\f': stop = 'f'; break; + case '\r': stop = 'r'; break; } - str = esc + 1; + saxdb_put_char(dest, '\\'); + saxdb_put_char(dest, stop); + ofs++; } - saxdb_put_string(dest, str); saxdb_put_char(dest, '"'); } @@ -249,11 +290,13 @@ void saxdb_start_record(struct saxdb_context *dest, const char *name, int complex) { saxdb_pre_object(dest); saxdb_put_qstring(dest, name); - saxdb_put_string(dest, " { "); + saxdb_put_string(dest, " {"); int_list_append(&dest->complex, complex); if (complex) { dest->indent++; saxdb_put_char(dest, '\n'); + } else { + saxdb_put_char(dest, ' '); } } @@ -386,7 +429,7 @@ static MODCMD_FUNC(cmd_write) { stop.tv_sec -= 1; stop.tv_usec += 1000000; } - reply("MSG_DB_WROTE_DB", db->name, stop.tv_sec, stop.tv_usec); + reply("MSG_DB_WROTE_DB", db->name, (unsigned long)stop.tv_sec, (unsigned long)stop.tv_usec); written++; } } @@ -405,7 +448,7 @@ static MODCMD_FUNC(cmd_writeall) { stop.tv_sec -= 1; stop.tv_usec += 1000000; } - reply("MSG_DB_WROTE_ALL", stop.tv_sec, stop.tv_usec); + reply("MSG_DB_WROTE_ALL", (unsigned long)stop.tv_sec, (unsigned long)stop.tv_usec); return 1; } @@ -529,21 +572,19 @@ write_database_helper(struct saxdb_context *ctx, struct dict *db) { int write_database(FILE *out, struct dict *db) { - struct saxdb_context ctx; + struct saxdb_context *ctx; int res; - ctx.output = out; - ctx.indent = 0; - int_list_init(&ctx.complex); - if (!(res = setjmp(ctx.jbuf))) { - write_database_helper(&ctx, db); + ctx = saxdb_open_context(out); + if (!(res = setjmp(*saxdb_jmp_buf(ctx)))) { + write_database_helper(ctx, db); } else { log_module(MAIN_LOG, LOG_ERROR, "Exception %d caught while writing to stream", res); - int_list_clean(&ctx.complex); + ctx->complex.used = 0; /* Squelch asserts about unbalanced output. */ + saxdb_close_context(ctx, 0); return 1; } - assert(ctx.complex.used == 0); - int_list_clean(&ctx.complex); + saxdb_close_context(ctx, 0); return 0; } @@ -554,14 +595,28 @@ saxdb_open_context(FILE *file) { assert(file); ctx = calloc(1, sizeof(*ctx)); ctx->output = file; + ctx->obuf.size = SAXDB_BUFFER_SIZE; + ctx->obuf.list = calloc(1, ctx->obuf.size); int_list_init(&ctx->complex); return ctx; } +jmp_buf * +saxdb_jmp_buf(struct saxdb_context *ctx) { + return &ctx->jbuf; +} + + void -saxdb_close_context(struct saxdb_context *ctx) { +saxdb_close_context(struct saxdb_context *ctx, int close_file) { assert(ctx->complex.used == 0); + saxdb_flush(ctx); int_list_clean(&ctx->complex); + free(ctx->obuf.list); + if (close_file) + fclose(ctx->output); + else + fflush(ctx->output); free(ctx); }