]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
config: Add file size and nanosecond resolution fields to the cached modified config...
authorRichard Mudgett <rmudgett@digium.com>
Wed, 19 Feb 2014 19:05:00 +0000 (19:05 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Wed, 19 Feb 2014 19:05:00 +0000 (19:05 +0000)
Repeatedly modifying config files and reloading too fast sometimes fails
to reload the configuration because the cached modification timestamp has
one second resolution.

* Added file size and nanosecond resolution fields to the cached config
file modification timestamp information.  Now if the file size changes or
the file system supports nanosecond resolution the modified file has a
better chance of being detected for reload.

* Added a missing unlock in an off-nominal code path.

(closes issue AST-1303)

Review: https://reviewboard.asterisk.org/r/3235/
........

Merged revisions 408387 from http://svn.asterisk.org/svn/asterisk/branches/1.8

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/11@408388 65c4cc65-6c06-0410-ace0-fbb531ad65f3

main/config.c

index 985a58fec73805c6605deffa21544889d5a70210..248493dbbdcc9d440d382a58a52b1cadfb24cc8a 100644 (file)
@@ -88,7 +88,12 @@ struct cache_file_mtime {
        AST_LIST_ENTRY(cache_file_mtime) list;
        AST_LIST_HEAD_NOLOCK(includes, cache_file_include) includes;
        unsigned int has_exec:1;
-       time_t mtime;
+       /*! stat() file size */
+       unsigned long stat_size;
+       /*! stat() file modtime nanoseconds */
+       unsigned long stat_mtime_nsec;
+       /*! stat() file modtime seconds since epoc */
+       time_t stat_mtime;
 
        /*! String stuffed in filename[] after the filename string. */
        const char *who_asked;
@@ -1180,6 +1185,61 @@ enum config_cache_attribute_enum {
        ATTRIBUTE_EXEC = 1,
 };
 
+/*!
+ * \internal
+ * \brief Clear the stat() data in the cached file modtime struct.
+ *
+ * \param cfmtime Cached file modtime.
+ *
+ * \return Nothing
+ */
+static void cfmstat_clear(struct cache_file_mtime *cfmtime)
+{
+       cfmtime->stat_size = 0;
+       cfmtime->stat_mtime_nsec = 0;
+       cfmtime->stat_mtime = 0;
+}
+
+/*!
+ * \internal
+ * \brief Save the stat() data to the cached file modtime struct.
+ *
+ * \param cfmtime Cached file modtime.
+ * \param statbuf Buffer filled in by stat().
+ *
+ * \return Nothing
+ */
+static void cfmstat_save(struct cache_file_mtime *cfmtime, struct stat *statbuf)
+{
+       cfmtime->stat_size = statbuf->st_size;
+#if defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || (defined(_POSIX_C_SOURCE) && 200809L <= _POSIX_C_SOURCE) || (defined(_XOPEN_SOURCE) && 700 <= _XOPEN_SOURCE)
+       cfmtime->stat_mtime_nsec = statbuf->st_mtim.tv_nsec;
+#else
+       cfmtime->stat_mtime_nsec = statbuf->st_mtimensec;
+#endif
+       cfmtime->stat_mtime = statbuf->st_mtime;
+}
+
+/*!
+ * \internal
+ * \brief Compare the stat() data with the cached file modtime struct.
+ *
+ * \param cfmtime Cached file modtime.
+ * \param statbuf Buffer filled in by stat().
+ *
+ * \retval non-zero if different.
+ */
+static int cfmstat_cmp(struct cache_file_mtime *cfmtime, struct stat *statbuf)
+{
+       struct cache_file_mtime cfm_buf;
+
+       cfmstat_save(&cfm_buf, statbuf);
+
+       return cfmtime->stat_size != cfm_buf.stat_size
+               || cfmtime->stat_mtime != cfm_buf.stat_mtime
+               || cfmtime->stat_mtime_nsec != cfm_buf.stat_mtime_nsec;
+}
+
 static void config_cache_attribute(const char *configfile, enum config_cache_attribute_enum attrtype, const char *filename, const char *who_asked)
 {
        struct cache_file_mtime *cfmtime;
@@ -1202,10 +1262,11 @@ static void config_cache_attribute(const char *configfile, enum config_cache_att
                AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
        }
 
-       if (!stat(configfile, &statbuf))
-               cfmtime->mtime = 0;
-       else
-               cfmtime->mtime = statbuf.st_mtime;
+       if (!stat(configfile, &statbuf)) {
+               cfmstat_clear(cfmtime);
+       } else {
+               cfmstat_save(cfmtime, &statbuf);
+       }
 
        switch (attrtype) {
        case ATTRIBUTE_INCLUDE:
@@ -1587,14 +1648,19 @@ static struct ast_config *config_text_file_load(const char *database, const char
                        }
                        if (!cfmtime) {
                                cfmtime = cfmtime_new(fn, who_asked);
-                               if (!cfmtime)
+                               if (!cfmtime) {
+                                       AST_LIST_UNLOCK(&cfmtime_head);
                                        continue;
+                               }
                                /* Note that the file mtime is initialized to 0, i.e. 1970 */
                                AST_LIST_INSERT_SORTALPHA(&cfmtime_head, cfmtime, list, filename);
                        }
                }
 
-               if (cfmtime && (!cfmtime->has_exec) && (cfmtime->mtime == statbuf.st_mtime) && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
+               if (cfmtime
+                       && !cfmtime->has_exec
+                       && !cfmstat_cmp(cfmtime, &statbuf)
+                       && ast_test_flag(&flags, CONFIG_FLAG_FILEUNCHANGED)) {
                        /* File is unchanged, what about the (cached) includes (if any)? */
                        int unchanged = 1;
                        AST_LIST_TRAVERSE(&cfmtime->includes, cfinclude, list) {
@@ -1651,8 +1717,9 @@ static struct ast_config *config_text_file_load(const char *database, const char
                        return NULL;
                }
 
-               if (cfmtime)
-                       cfmtime->mtime = statbuf.st_mtime;
+               if (cfmtime) {
+                       cfmstat_save(cfmtime, &statbuf);
+               }
 
                if (!(f = fopen(fn, "r"))) {
                        ast_debug(1, "No file to parse: %s\n", fn);