diff options
author | Joern Engel <joern@logfs.org> | 2015-02-17 11:13:15 -0800 |
---|---|---|
committer | Joern Engel <joern@logfs.org> | 2015-02-17 11:50:09 -0800 |
commit | e3b0e34a3ea0cd91118345f9dca7242ad2083736 (patch) | |
tree | c7187e5dad0dc3e36b8329e5e092c0f21459649e | |
parent | bbb023f21912ab5c23201834a74a091222d308e2 (diff) | |
download | cancd-e3b0e34a3ea0cd91118345f9dca7242ad2083736.tar.gz |
Cache open/stat for performance
Open fd stays valid for 60s. It will actually stick around forever,
there is no garbage collection for stale files yet.
Signed-off-by: Joern Engel <joern@logfs.org>
-rw-r--r-- | cancd.c | 66 |
1 files changed, 51 insertions, 15 deletions
@@ -105,6 +105,9 @@ struct source_ip { const char *filename; const char *tmpfilename; int had_newline; + int fd; + uint64_t filesize; + uint64_t reopen_time; }; void handler(int signum) @@ -322,7 +325,7 @@ static int do_write(int fd, const void *buf, size_t count) return 0; } -static int write_formatted(int fd, struct source_ip *sip, char *buf, int count) +static int write_formatted(struct source_ip *sip, char *buf, int count) { const char *format = "%b %d %H:%M:%S "; char *end; @@ -340,19 +343,21 @@ static int write_formatted(int fd, struct source_ip *sip, char *buf, int count) while (count > 1) { if (sip->had_newline) { n = strftime(timestr, sizeof(timestr), format, tm); - err = do_write(fd, timestr, n); + err = do_write(sip->fd, timestr, n); if (err) return err; } end = strchr(buf, 0xa); if (!end) { /* no newline, just write what we have */ - do_write(fd, buf, count - 1); + err = do_write(sip->fd, buf, count - 1); + if (err) + return err; sip->had_newline = 0; break; } len = end - buf + 1; - err = do_write(fd, buf, len); + err = do_write(sip->fd, buf, len); if (err) return err; buf += len; @@ -372,6 +377,7 @@ static struct source_ip *get_source_ip(struct sockaddr_in *addr) if (!sip) { sip = calloc(1, sizeof(*sip)); sip->had_newline = 1; + sip->fd = -1; sip->tmpfilename = get_path(&addr->sin_addr); err = btree_insert32(&btree, key, sip); assert(!err); @@ -398,6 +404,10 @@ static const char *copy_tmpfile(struct source_ip *sip) char buf[4096]; ssize_t count; + if (sip->fd >= 0) { + close(sip->fd); + sip->fd = -1; + } fd = open(name, O_WRONLY | O_APPEND | O_CREAT, 0644); if (fd < 0) { syslog(LOG_ERR, "Unable to open \"%s\": %s", name, @@ -427,9 +437,17 @@ out: return NULL; } +uint64_t gethrtime(void) +{ + struct timespec tod; + + clock_gettime(CLOCK_MONOTONIC, &tod); + return tod.tv_sec * 1000000000ULL + tod.tv_nsec; +} + static void do_output(char *buf, int len, struct sockaddr_in *addr, socklen_t socklen) { - int fd, err; + int err; struct stat stat; const char *name; struct source_ip *sip = get_source_ip(addr); @@ -438,17 +456,35 @@ static void do_output(char *buf, int len, struct sockaddr_in *addr, socklen_t so if (!name) return; - fd = open(name, O_WRONLY | O_APPEND | O_CREAT, 0644); - if (fd < 0) { - syslog(LOG_ERR, "Unable to open \"%s\": %s", name, strerror(errno)); - return; + /* + * We cache the open fd for 60s. We also cache the filesize. + * This reduces cpu overhead a bit, but means logrotate has to + * keep the file around for 60s after rotation and we can + * overshoot the size limit a bit. + */ + if (sip->fd >= 0 && gethrtime() > sip->reopen_time) { + close(sip->fd); + sip->fd = -1; } - err = fstat(fd, &stat); - if (err || stat.st_size > size_limit) - goto out; - write_formatted(fd, sip, buf, len); -out: - close(fd); + + if (sip->fd < 0) { + sip->fd = open(name, O_WRONLY | O_APPEND | O_CREAT, 0644); + if (sip->fd < 0) { + syslog(LOG_ERR, "Unable to open \"%s\": %s", name, strerror(errno)); + return; + } + err = fstat(sip->fd, &stat); + if (err) { + close(sip->fd); + sip->fd = -1; + return; + } + sip->filesize = stat.st_size; + sip->reopen_time = gethrtime() + 60000000000ULL; /* 60s */ + } + if (sip->filesize > size_limit) + return; + write_formatted(sip, buf, len); } static int set_blocking(int blocking) |