diff options
author | Carlos Martín Nieto <cmn@dwim.me> | 2014-03-18 17:54:32 +0100 |
---|---|---|
committer | Carlos Martín Nieto <cmn@dwim.me> | 2014-04-18 16:06:04 +0200 |
commit | c047317e400efc75b07aa0fff61ee1fcd794e74e (patch) | |
tree | b3d862f55d2d55d879407a9a75d5fdfa537fbe4b /src/config_file.c | |
parent | 29c4cb0965b67ad1ae7f640dfee67cf3ce358c26 (diff) | |
download | libgit2-c047317e400efc75b07aa0fff61ee1fcd794e74e.tar.gz |
config: make refresh atomic
Current code sets the active map to a new one and builds it whilst it's
active. This is a race condition with someone else trying to access the
same config.
Instead, let's build up our new map and swap the active and new one.
Diffstat (limited to 'src/config_file.c')
-rw-r--r-- | src/config_file.c | 39 |
1 files changed, 16 insertions, 23 deletions
diff --git a/src/config_file.c b/src/config_file.c index fcf9cab04..437a5c592 100644 --- a/src/config_file.c +++ b/src/config_file.c @@ -107,7 +107,7 @@ typedef struct { diskfile_backend *snapshot_from; } diskfile_readonly_backend; -static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth); +static int config_parse(git_strmap *values, diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth); static int parse_variable(struct reader *reader, char **var_name, char **var_value); static int config_write(diskfile_backend *cfg, const char *key, const regex_t *preg, const char *value); static char *escape_value(const char *ptr); @@ -243,7 +243,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level) if (res == GIT_ENOTFOUND) return 0; - if (res < 0 || (res = config_parse(b, reader, level, 0)) < 0) { + if (res < 0 || (res = config_parse(b->header.values, b, reader, level, 0)) < 0) { free_vars(b->header.values); b->header.values = NULL; } @@ -256,47 +256,41 @@ static int config_open(git_config_backend *cfg, git_config_level_t level) static int config_refresh(git_config_backend *cfg) { - int res = 0, updated = 0, any_updated = 0; + int error = 0, updated = 0, any_updated = 0; diskfile_backend *b = (diskfile_backend *)cfg; - git_strmap *old_values; + git_strmap *values = NULL; struct reader *reader = NULL; uint32_t i; for (i = 0; i < git_array_size(b->readers); i++) { reader = git_array_get(b->readers, i); - - res = git_futils_readbuffer_updated( + error = git_futils_readbuffer_updated( &reader->buffer, reader->file_path, &reader->file_mtime, &reader->file_size, &updated); - if (res < 0) - return (res == GIT_ENOTFOUND) ? 0 : res; + if (error < 0) + return (error == GIT_ENOTFOUND) ? 0 : error; if (updated) any_updated = 1; } if (!any_updated) - return (res == GIT_ENOTFOUND) ? 0 : res; + return (error == GIT_ENOTFOUND) ? 0 : error; - /* need to reload - store old values and prep for reload */ - old_values = b->header.values; - if ((res = git_strmap_alloc(&b->header.values)) < 0) { - b->header.values = old_values; + + if ((error = git_strmap_alloc(&values)) < 0) goto cleanup; - } - if ((res = config_parse(b, reader, b->level, 0)) < 0) { - free_vars(b->header.values); - b->header.values = old_values; + if ((error = config_parse(values, b, reader, b->level, 0)) < 0) goto cleanup; - } - free_vars(old_values); + values = git__swap(b->header.values, values); cleanup: + free_vars(values); git_buf_free(&reader->buffer); - return res; + return error; } static void backend_free(git_config_backend *_backend) @@ -1218,7 +1212,7 @@ static int included_path(git_buf *out, const char *dir, const char *path) return git_path_join_unrooted(out, path, dir, NULL); } -static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth) +static int config_parse(git_strmap *values, diskfile_backend *cfg_file, struct reader *reader, git_config_level_t level, int depth) { int c; char *current_section = NULL; @@ -1228,7 +1222,6 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c git_buf buf = GIT_BUF_INIT; int result = 0; uint32_t reader_idx; - git_strmap *values = cfg_file->header.values; if (depth >= MAX_INCLUDE_DEPTH) { giterr_set(GITERR_CONFIG, "Maximum config include depth reached"); @@ -1327,7 +1320,7 @@ static int config_parse(diskfile_backend *cfg_file, struct reader *reader, git_c &r->file_size, NULL)) < 0) break; - result = config_parse(cfg_file, r, level, depth+1); + result = config_parse(values, cfg_file, r, level, depth+1); r = git_array_get(cfg_file->readers, index); git_buf_free(&r->buffer); |