*/
int ast_sorcery_object_set_extended(const void *object, const char *name, const char *value);
+/*!
+ * \brief Get whether an object contains dynamic contents or not
+ *
+ * \param object Pointer to a sorcery object
+ *
+ * \since 19
+ * \since 18.3.0
+ * \since 16.17.0
+ */
+unsigned int ast_sorcery_object_has_dynamic_contents(const void *object);
+
+/*!
+ * \brief Set the dynamic contents flag on a sorcery object
+ *
+ * \param object Pointer to a sorcery object
+ *
+ * \since 19
+ * \since 18.3.0
+ * \since 16.17.0
+ */
+void ast_sorcery_object_set_has_dynamic_contents(const void *object);
+
/*!
* \brief ao2 object comparator based on sorcery id.
*/
/*! \brief Time that the object was created */
struct timeval created;
+
+ /*! \brief Whether this object has dynamic contents or not */
+ unsigned int has_dynamic_contents:1;
};
/*! \brief Structure for registered object type */
return 0;
}
+unsigned int ast_sorcery_object_has_dynamic_contents(const void *object)
+{
+ const struct ast_sorcery_object_details *details = object;
+
+ return details->object->has_dynamic_contents;
+}
+
+void ast_sorcery_object_set_has_dynamic_contents(const void *object)
+{
+ const struct ast_sorcery_object_details *details = object;
+
+ details->object->has_dynamic_contents = 1;
+}
+
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
{
RAII_VAR(struct ast_sorcery_object_type *, object_type, ao2_find(sorcery->types, type, OBJ_KEY), ao2_cleanup);
return 0;
}
+ /* Hosts can produce dynamic content, so mark the identify as such */
+ ast_sorcery_object_set_has_dynamic_contents(obj);
+
/* Resolve the match addresses now */
i = ao2_iterator_init(identify->hosts, 0);
while ((current_string = ao2_iterator_next(&i))) {
/*! \brief Configuration is invalid in some way, force reload */
unsigned int configuration_invalid:1;
+ /*! \brief Configuration contains at least one object with dynamic contents */
+ unsigned int has_dynamic_contents:1;
+
/*! \brief Filename of the configuration file */
char filename[];
};
static void sorcery_config_internal_load(void *data, const struct ast_sorcery *sorcery, const char *type, unsigned int reload)
{
struct sorcery_config *config = data;
- struct ast_flags flags = { reload && !config->configuration_invalid ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+ struct ast_flags flags = { reload && !config->configuration_invalid && !config->has_dynamic_contents ? CONFIG_FLAG_FILEUNCHANGED : 0 };
struct ast_config *cfg = ast_config_load2(config->filename, config->uuid, flags);
struct ast_category *category = NULL;
RAII_VAR(struct ao2_container *, objects, NULL, ao2_cleanup);
const char *id = NULL;
unsigned int buckets = 0;
+ unsigned int has_dynamic_contents = 0;
if (!cfg) {
ast_log(LOG_ERROR, "Unable to load config file '%s'\n", config->filename);
ast_log(LOG_NOTICE, "Retaining existing configuration for object of type '%s' with id '%s'\n", type, id);
}
+ /* We store the dynamic contents state until the end in case this reload or load
+ * gets rolled back.
+ */
+ has_dynamic_contents |= ast_sorcery_object_has_dynamic_contents(obj);
+
ao2_link(objects, obj);
}
+ config->has_dynamic_contents = has_dynamic_contents;
ao2_global_obj_replace_unref(config->objects, objects);
ast_config_destroy(cfg);
}