diff options
author | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-07-19 15:28:34 +0200 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2009-07-19 15:28:34 +0200 |
commit | 651794575c844fe25a717d77bd088c51383067f0 (patch) | |
tree | d4dd79f189ebdb933266d354aa66f42b7571f4b4 /src/cache_iterators.c | |
parent | a1d03b775376aa8545ec9a0e89381b659e4d28ed (diff) | |
download | conntrack-tools-651794575c844fe25a717d77bd088c51383067f0.tar.gz conntrack-tools-651794575c844fe25a717d77bd088c51383067f0.zip |
conntrackd: rework commit not to fork a child process
This patch reworks the commit phase to avoid the forking. This is
particularly useful in active-active setups in which one node
has to commit the external cache while it is receiving new entries
to be added in the external cache. This results in really high
commit times due to the penalty of the copy-on-write that fork
performs.
The default number of steps in one run loop is limited to 64 by now.
No option to tune this parameter is still available via the
configuration file.
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
Diffstat (limited to 'src/cache_iterators.c')
-rw-r--r-- | src/cache_iterators.c | 79 |
1 files changed, 58 insertions, 21 deletions
diff --git a/src/cache_iterators.c b/src/cache_iterators.c index b6688e9..c7183fd 100644 --- a/src/cache_iterators.c +++ b/src/cache_iterators.c @@ -21,6 +21,7 @@ #include "log.h" #include "conntrackd.h" #include "netlink.h" +#include "event.h" #include <libnetfilter_conntrack/libnetfilter_conntrack.h> #include <sched.h> @@ -174,37 +175,73 @@ static int do_commit_master(void *data, void *n) return 0; } -/* no need to clone, called from child process */ -void cache_commit(struct cache *c, struct nfct_handle *h) +void cache_commit(struct cache *c, struct nfct_handle *h, int clientfd) { - unsigned int commit_ok = c->stats.commit_ok; - unsigned int commit_fail = c->stats.commit_fail; + unsigned int commit_ok, commit_fail; struct __commit_container tmp = { .h = h, .c = c, }; - struct timeval commit_start, commit_stop, res; + struct timeval commit_stop, res; - gettimeofday(&commit_start, NULL); - /* commit master conntrack first, then related ones */ - hashtable_iterate(c->h, &tmp, do_commit_master); - hashtable_iterate(c->h, &tmp, do_commit_related); - gettimeofday(&commit_stop, NULL); - timersub(&commit_stop, &commit_start, &res); + switch(STATE_SYNC(commit).state) { + case COMMIT_STATE_INACTIVE: + gettimeofday(&STATE_SYNC(commit).stats.start, NULL); + STATE_SYNC(commit).stats.ok = c->stats.commit_ok; + STATE_SYNC(commit).stats.fail = c->stats.commit_fail; + STATE_SYNC(commit).clientfd = clientfd; + case COMMIT_STATE_MASTER: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + do_commit_master); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_MASTER; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return; + } + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + case COMMIT_STATE_RELATED: + STATE_SYNC(commit).current = + hashtable_iterate_limit(c->h, &tmp, + STATE_SYNC(commit).current, + CONFIG(general).commit_steps, + do_commit_related); + if (STATE_SYNC(commit).current < CONFIG(hashsize)) { + STATE_SYNC(commit).state = COMMIT_STATE_RELATED; + /* give it another step as soon as possible */ + write_evfd(STATE_SYNC(commit).evfd); + return; + } + /* calculate the time that commit has taken */ + gettimeofday(&commit_stop, NULL); + timersub(&commit_stop, &STATE_SYNC(commit).stats.start, &res); + + /* calculate new entries committed */ + commit_ok = c->stats.commit_ok - STATE_SYNC(commit).stats.ok; + commit_fail = + c->stats.commit_fail - STATE_SYNC(commit).stats.fail; - /* calculate new entries committed */ - commit_ok = c->stats.commit_ok - commit_ok; - commit_fail = c->stats.commit_fail - commit_fail; + /* log results */ + dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); - /* log results */ - dlog(LOG_NOTICE, "Committed %u new entries", commit_ok); + if (commit_fail) + dlog(LOG_NOTICE, "%u entries can't be " + "committed", commit_fail); - if (commit_fail) - dlog(LOG_NOTICE, "%u entries can't be " - "committed", commit_fail); + dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", + res.tv_sec, res.tv_usec); - dlog(LOG_NOTICE, "commit has taken %lu.%06lu seconds", - res.tv_sec, res.tv_usec); + /* prepare the state machine for new commits */ + STATE_SYNC(commit).current = 0; + STATE_SYNC(commit).state = COMMIT_STATE_INACTIVE; + + /* Close the client socket now that we're done. */ + close(STATE_SYNC(commit).clientfd); + } } static int do_flush(void *data, void *n) |