From 1fa05896bdeef9a9edff66b22a456c4dbd6de407 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Thu, 21 Apr 2016 11:01:59 +0200 Subject: [PATCH 04/14] SYSDB: Add a second, timestamp-only ldb cache Uses the generic functions in sysdb_init.c to open a new ldb database. The path to the database and the ldb context are stored in the sysdb_ctx. The database will be used to store ephemeral attributes such as timestamps. Because these attributes are not required for SSSD operation and the intent is for writes to this cache to be very fast, the database is opened with LDB_FLG_NOSYNC flag. At the same time, none of the attributes of the cache is required for sssd operation, so if we fail to open the database, we just start over. Adds a separate base LDIF with attributes that are supposed to be indexed in the timestamp database as well as a separate timestamp cache version. --- src/db/sysdb_init.c | 134 +++++++++++++++++++++++++++++++++++++++++++++++++ src/db/sysdb_private.h | 24 +++++++++ 2 files changed, 158 insertions(+) diff --git a/src/db/sysdb_init.c b/src/db/sysdb_init.c index 6426b940a98e9efd3a9e50a97ce14af9daa78699..49a8d2b914776a3d506ed911bc772f3b16cc1333 100644 --- a/src/db/sysdb_init.c +++ b/src/db/sysdb_init.c @@ -297,6 +297,17 @@ static errno_t sysdb_cache_create_empty(struct ldb_context *ldb, return EOK; } +static errno_t sysdb_ts_cache_upgrade(TALLOC_CTX *mem_ctx, + struct sysdb_ctx *sysdb, + struct ldb_context *ldb, + struct sss_domain_info *domain, + const char *cur_version, + const char **_new_version) +{ + /* Currently the sysdb cache only has one version */ + return EFAULT; +} + static errno_t sysdb_domain_cache_upgrade(TALLOC_CTX *mem_ctx, struct sysdb_ctx *sysdb, struct ldb_context *ldb, @@ -597,6 +608,114 @@ done: return ret; } +static int sysdb_timestamp_cache_connect(struct sysdb_ctx *sysdb, + struct sss_domain_info *domain, + bool allow_upgrade) +{ + errno_t ret; + const char *version; + TALLOC_CTX *tmp_ctx; + struct ldb_context *ldb; + + if (sysdb->ldb_ts_file == NULL) { + DEBUG(SSSDBG_TRACE_FUNC, "No timestamp cache for %s\n", domain->name); + return EOK; + } + + tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + return ENOMEM; + } + + ret = sysdb_cache_connect(tmp_ctx, domain, + sysdb->ldb_ts_file, LDB_FLG_NOSYNC, + SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF, + &ldb, &version); + switch (ret) { + case ERR_SYSDB_VERSION_TOO_OLD: + if (allow_upgrade == false) { + DEBUG(SSSDBG_FATAL_FAILURE, + "DB version too old [%s], expected [%s] for domain %s!\n", + version, SYSDB_VERSION, domain->name); + break; + } + + ret = sysdb_ts_cache_upgrade(tmp_ctx, sysdb, ldb, domain, version, + &version); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not upgrade the timestamp ldb file (%d) (%s)\n", + ret, sss_strerror(ret)); + break; + } + + /* The version should now match SYSDB_VERSION. + * If not, it means we didn't match any of the + * known older versions. The DB might be + * corrupt or generated by a newer version of + * SSSD. + */ + ret = sysdb_version_check(SYSDB_TS_VERSION, version); + if (ret == EOK) { + /* The cache has been upgraded. + * We need to reopen the LDB to ensure that + * any changes made above take effect. + */ + ret = sysdb_ldb_reconnect(tmp_ctx, + sysdb->ldb_ts_file, + LDB_FLG_NOSYNC, + &ldb); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not reopen the timestamp ldb file (%d) (%s)\n", + ret, sss_strerror(ret)); + } + } + break; + case ERR_SYSDB_VERSION_TOO_NEW: + DEBUG(SSSDBG_MINOR_FAILURE, + "DB version too new [%s], expected [%s] for domain %s!\n", + version, SYSDB_TS_VERSION, domain->name); + break; + default: + break; + } + + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "The timestamps cache could not be opened. " + "Throwing away the database and opening a new one\n"); + + ret = unlink(sysdb->ldb_ts_file); + if (ret != EOK && errno != ENOENT) { + ret = errno; + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not delete the timestamp ldb file (%d) (%s)\n", + ret, sss_strerror(ret)); + return ret; + } + + /* Now the connect must succeed because the previous cache doesn't + * exist anymore. + */ + ret = sysdb_cache_connect(tmp_ctx, domain, + sysdb->ldb_ts_file, LDB_FLG_NOSYNC, + SYSDB_TS_VERSION, SYSDB_TS_BASE_LDIF, + &ldb, &version); + if (ret != EOK) { + DEBUG(SSSDBG_MINOR_FAILURE, + "Could not delete the timestamp ldb file (%d) (%s)\n", + ret, sss_strerror(ret)); + } + } + + if (ret == EOK) { + sysdb->ldb_ts = talloc_steal(sysdb, ldb); + } + talloc_free(tmp_ctx); + return ret; +} + int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx, struct sss_domain_info *domain, const char *db_path, @@ -628,6 +747,21 @@ int sysdb_domain_init_internal(TALLOC_CTX *mem_ctx, "DB File for %s: %s\n", domain->name, sysdb->ldb_file); ret = sysdb_domain_cache_connect(sysdb, domain, allow_upgrade); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not open the sysdb cache [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + + ret = sysdb_timestamp_cache_connect(sysdb, domain, allow_upgrade); + if (ret != EOK) { + DEBUG(SSSDBG_CRIT_FAILURE, + "Could not open the timestamp cache [%d]: %s\n", + ret, sss_strerror(ret)); + goto done; + } + done: if (ret == EOK) { *_ctx = talloc_steal(mem_ctx, sysdb); diff --git a/src/db/sysdb_private.h b/src/db/sysdb_private.h index a78a9be2f780cf04181032745e13ab609bfa3f5d..5f7a1ed6f82726b0f6c81fb79eb77cdb3d1612de 100644 --- a/src/db/sysdb_private.h +++ b/src/db/sysdb_private.h @@ -84,11 +84,35 @@ "cn: ranges\n" \ "\n" +/* The timestamp cache has its own versioning */ +#define SYSDB_TS_VERSION_0_1 "0.1" + +#define SYSDB_TS_VERSION SYSDB_TS_VERSION_0_1 + +#define SYSDB_TS_BASE_LDIF \ + "dn: @ATTRIBUTES\n" \ + "dn: CASE_INSENSITIVE\n" \ + "\n" \ + "dn: @INDEXLIST\n" \ + "@IDXATTR: lastUpdate\n" \ + "@IDXATTR: dataExpireTimestamp\n" \ + "@IDXONE: 1\n" \ + "\n" \ + "dn: cn=sysdb\n" \ + "cn: sysdb\n" \ + "version: " SYSDB_TS_VERSION "\n" \ + "description: base object\n" \ + "\n" \ + #include "db/sysdb.h" struct sysdb_ctx { struct ldb_context *ldb; char *ldb_file; + + struct ldb_context *ldb_ts; + char *ldb_ts_file; + int transaction_nesting; }; -- 2.4.11