#include "master-service-settings.h"
#include <unistd.h>
+#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>
errno = saved_errno;
}
+static int master_service_binary_config_cache_get(const char *cache_dir,
+ const char *input_path)
+{
+ if (cache_dir == NULL)
+ return -1;
+
+ const char *cache_path =
+ master_service_get_binary_config_cache_path(cache_dir, input_path);
+ int fd = open(cache_path, O_RDONLY);
+ if (fd == -1 && errno != ENOENT)
+ i_error("Binary config cache: open(%s) failed: %m", cache_path);
+ return fd;
+}
+
static int
master_service_open_config(struct master_service *service,
const struct master_service_settings_input *input,
- const char **path_r, const char **error_r)
+ const char *cache_dir,
+ const char **path_r, bool *cached_config_r,
+ const char **error_r)
{
struct stat st;
const char *path;
int fd = -1;
+ *cached_config_r = FALSE;
*path_r = path = input->config_path != NULL ? input->config_path :
master_service_get_config_path(service);
+ if ((fd = master_service_binary_config_cache_get(cache_dir, path)) != -1) {
+ *cached_config_r = TRUE;
+ return fd;
+ }
if (!service->config_path_from_master &&
!service->config_path_changed_with_param &&
}
}
-int master_service_settings_read(struct master_service *service,
+static int
+master_service_settings_read_int(struct master_service *service,
const struct master_service_settings_input *input,
+ const char *cache_dir,
struct master_service_settings_output *output_r,
const char **error_r)
{
const char *path = NULL, *value, *error;
+ bool cached_config = FALSE;
int ret, fd = -1;
i_zero(output_r);
/* Open config via socket if possible. If it doesn't work,
execute doveconf -F. */
T_BEGIN {
- fd = master_service_open_config(service, input, &path,
- &error);
+ fd = master_service_open_config(service, input,
+ cache_dir, &path,
+ &cached_config, &error);
} T_END_PASS_STR_IF(fd == -1, &error);
if (fd == -1) {
if (errno == EACCES)
enum settings_read_flags read_flags =
!input->no_protocol_filter ? 0 :
SETTINGS_READ_NO_PROTOCOL_FILTER;
+ if (cached_config)
+ read_flags |= SETTINGS_READ_CHECK_CACHE_TIMESTAMPS;
ret = settings_read(service->settings_root, fd, path,
service_name, protocol_name, read_flags,
&output_r->specific_protocols,
&error);
+ if (ret == 0 && cached_config) {
+ /* out-of-date binary config cache */
+ i_close_fd(&fd);
+ return master_service_settings_read_int(service, input,
+ NULL, output_r, error_r);
+ }
if (input->return_config_fd)
output_r->config_fd = fd;
else
return 0;
}
+int master_service_settings_read(struct master_service *service,
+ const struct master_service_settings_input *input,
+ struct master_service_settings_output *output_r,
+ const char **error_r)
+{
+ return master_service_settings_read_int(service, input,
+ getenv("DOVECOT_CONFIG_CACHE"),
+ output_r, error_r);
+}
+
int master_service_settings_read_simple(struct master_service *service,
const char **error_r)
{