From 5bcbe2125b18160f6ad348b15f8036ffedc15770 Mon Sep 17 00:00:00 2001 From: Nicolas Williams Date: Tue, 10 Oct 2017 13:06:21 -0500 Subject: [PATCH] Add hdb_set_sync() method --- lib/hdb/db.c | 43 ++++++++++++++++++------------ lib/hdb/db3.c | 62 +++++++++++++++++++++++--------------------- lib/hdb/hdb-ldap.c | 8 ++++++ lib/hdb/hdb-mdb.c | 18 +++++++++++++ lib/hdb/hdb-mitdb.c | 43 +++++++++++++++++++++++++----- lib/hdb/hdb-sqlite.c | 10 +++++++ lib/hdb/hdb.h | 10 ++++++- 7 files changed, 140 insertions(+), 54 deletions(-) diff --git a/lib/hdb/db.c b/lib/hdb/db.c index c6cf58813..4cee8d009 100644 --- a/lib/hdb/db.c +++ b/lib/hdb/db.c @@ -44,6 +44,7 @@ typedef struct { HDB hdb; /* generic members */ int lock_fd; /* DB-specific */ + int do_sync; /* DB-specific */ } DB1_HDB; static krb5_error_code @@ -76,6 +77,25 @@ DB_destroy(krb5_context context, HDB *db) return ret; } +static krb5_error_code +DB_set_sync(krb5_context context, HDB *db, int on) +{ + DB1_HDB *db1 = (DB1_HDB *)db; + DB *d = (DB*)db->hdb_db; + krb5_error_code ret = 0; + + db1->do_sync = on; + if (on) { + ret = (*d->sync)(d, 0); + if (ret == -1) { + ret = errno; + krb5_set_error_message(context, ret, "Database %s put sync error: %s", + db->hdb_name, strerror(ret)); + } + } + return ret; +} + static krb5_error_code DB_lock(krb5_context context, HDB *db, int operation) { @@ -203,6 +223,7 @@ static krb5_error_code DB__put(krb5_context context, HDB *db, int replace, krb5_data key, krb5_data value) { + DB1_HDB *db1 = (DB1_HDB *)db; DB *d = (DB*)db->hdb_db; DBT k, v; int code; @@ -222,19 +243,14 @@ DB__put(krb5_context context, HDB *db, int replace, if(code == 1) { return HDB_ERR_EXISTS; } - code = (*d->sync)(d, 0); - if (code == -1) { - code = errno; - krb5_set_error_message(context, code, "Database %s put sync error: %s", - db->hdb_name, strerror(code)); - return code; - } - return 0; + + return db->hdb_set_sync(context, db, db1->do_sync); } static krb5_error_code DB__del(krb5_context context, HDB *db, krb5_data key) { + DB1_HDB *db1 = (DB1_HDB *)db; DB *d = (DB*)db->hdb_db; DBT k; krb5_error_code code; @@ -250,14 +266,7 @@ DB__del(krb5_context context, HDB *db, krb5_data key) db->hdb_name, strerror(code)); return code; } - code = (*d->sync)(d, 0); - if (code == -1) { - code = errno; - krb5_set_error_message(context, code, "Database %s del sync error: %s", - db->hdb_name, strerror(code)); - return code; - } - return 0; + return db->hdb_set_sync(context, db, db1->do_sync); } static DB * @@ -371,8 +380,10 @@ hdb_db1_create(krb5_context context, HDB **db, (*db)->hdb__put = DB__put; (*db)->hdb__del = DB__del; (*db)->hdb_destroy = DB_destroy; + (*db)->hdb_set_sync = DB_set_sync; (*db1)->lock_fd = -1; + (*db1)->do_sync = 1; return 0; } diff --git a/lib/hdb/db3.c b/lib/hdb/db3.c index cd2e33f06..0d41369d7 100644 --- a/lib/hdb/db3.c +++ b/lib/hdb/db3.c @@ -54,6 +54,7 @@ typedef struct { HDB hdb; /* generic members */ int lock_fd; /* DB3-specific */ + int do_sync; /* DB3-specific */ } DB3_HDB; @@ -91,6 +92,32 @@ DB_destroy(krb5_context context, HDB *db) return ret; } +static krb5_error_code +DB_set_sync(krb5_context context, HDB *db, int on) +{ + DB3_HDB *db3 = (DB3_HDB *)db; + DB *d = (DB*)db->hdb_db; + krb5_error_code ret = 0; + + db3->do_sync = on; + if (on) { + ret = (*d->sync)(d, 0); + if (ret) { + if (ret == EACCES || ret == ENOSPC || ret == EINVAL) { + krb5_set_error_message(context, ret, + "Database %s put sync error: %s", + db->hdb_name, strerror(ret)); + } else { + ret = HDB_ERR_UK_SERROR; + krb5_set_error_message(context, ret, + "Database %s put sync error: unknown (%d)", + db->hdb_name, ret); + } + } + } + return ret; +} + static krb5_error_code DB_lock(krb5_context context, HDB *db, int operation) { @@ -220,6 +247,7 @@ static krb5_error_code DB__put(krb5_context context, HDB *db, int replace, krb5_data key, krb5_data value) { + DB3_HDB *db3 = (DB3_HDB *)db; DB *d = (DB*)db->hdb_db; DBT k, v; int code; @@ -261,26 +289,13 @@ DB__put(krb5_context context, HDB *db, int replace, } return code; } - code = (*d->sync)(d, 0); - if (code) { - if (code == EACCES || code == ENOSPC || code == EINVAL) { - krb5_set_error_message(context, code, - "Database %s put sync error: %s", - db->hdb_name, strerror(code)); - } else { - code = HDB_ERR_UK_SERROR; - krb5_set_error_message(context, code, - "Database %s put sync error: unknown (%d)", - db->hdb_name, code); - } - return code; - } - return 0; + return db->hdb_set_sync(context, db, db3->do_sync); } static krb5_error_code DB__del(krb5_context context, HDB *db, krb5_data key) { + DB3_HDB *db3 = (DB3_HDB *)db; DB *d = (DB*)db->hdb_db; DBT k; krb5_error_code code; @@ -304,21 +319,7 @@ DB__del(krb5_context context, HDB *db, krb5_data key) } return code; } - code = (*d->sync)(d, 0); - if (code) { - if (code == EACCES || code == ENOSPC || code == EINVAL) { - krb5_set_error_message(context, code, - "Database %s del sync error: %s", - db->hdb_name, strerror(code)); - } else { - code = HDB_ERR_UK_SERROR; - krb5_set_error_message(context, code, - "Database %s del sync error: unknown (%d)", - db->hdb_name, code); - } - return code; - } - return 0; + return db->hdb_set_sync(context, db, db3->do_sync); } #define RD_CACHE_SZ 0x8000 /* Minimal read cache size */ @@ -485,6 +486,7 @@ hdb_db3_create(krb5_context context, HDB **db, (*db)->hdb__put = DB__put; (*db)->hdb__del = DB__del; (*db)->hdb_destroy = DB_destroy; + (*db)->hdb_set_sync = DB_set_sync; (*db3)->lock_fd = -1; return 0; diff --git a/lib/hdb/hdb-ldap.c b/lib/hdb/hdb-ldap.c index 18ecc1067..f204bfde7 100644 --- a/lib/hdb/hdb-ldap.c +++ b/lib/hdb/hdb-ldap.c @@ -1890,6 +1890,13 @@ LDAP_destroy(krb5_context context, HDB * db) return ret; } +static krb5_error_code +LDAP_set_sync(krb5_context context, HDB * db, int on) +{ + (void)on; + return 0; +} + static krb5_error_code hdb_ldap_common(krb5_context context, HDB ** db, @@ -2024,6 +2031,7 @@ hdb_ldap_common(krb5_context context, (*db)->hdb__put = NULL; (*db)->hdb__del = NULL; (*db)->hdb_destroy = LDAP_destroy; + (*db)->hdb_set_sync = LDAP_set_sync; return 0; } diff --git a/lib/hdb/hdb-mdb.c b/lib/hdb/hdb-mdb.c index 920d7780e..52d9aed7a 100644 --- a/lib/hdb/hdb-mdb.c +++ b/lib/hdb/hdb-mdb.c @@ -75,6 +75,15 @@ DB_destroy(krb5_context context, HDB *db) return ret; } +static krb5_error_code +DB_set_sync(krb5_context context, HDB *db, int on) +{ + mdb_info *mi = (mdb_info *)db->hdb_db; + + mdb_env_set_flags(mi->e, MDB_NOSYNC, !on); + return mdb_env_sync(mi->e, 0); +} + static krb5_error_code DB_lock(krb5_context context, HDB *db, int operation) { @@ -240,6 +249,10 @@ DB__put(krb5_context context, HDB *db, int replace, mdb_txn_abort(txn); else code = mdb_txn_commit(txn); + /* + * No need to call mdb_env_sync(); it's done automatically if MDB_NOSYNC is + * not set. + */ if(code == MDB_KEYEXIST) return HDB_ERR_EXISTS; return code; @@ -265,6 +278,10 @@ DB__del(krb5_context context, HDB *db, krb5_data key) mdb_txn_abort(txn); else code = mdb_txn_commit(txn); + /* + * No need to call mdb_env_sync(); it's done automatically if MDB_NOSYNC is + * not set. + */ if(code == MDB_NOTFOUND) return HDB_ERR_NOENTRY; return code; @@ -394,6 +411,7 @@ hdb_mdb_create(krb5_context context, HDB **db, (*db)->hdb__put = DB__put; (*db)->hdb__del = DB__del; (*db)->hdb_destroy = DB_destroy; + (*db)->hdb_set_sync = DB_set_sync; return 0; } #endif /* HAVE_LMDB */ diff --git a/lib/hdb/hdb-mitdb.c b/lib/hdb/hdb-mitdb.c index 188f62268..c9df36db2 100644 --- a/lib/hdb/hdb-mitdb.c +++ b/lib/hdb/hdb-mitdb.c @@ -91,6 +91,11 @@ salt: #include "hdb_locl.h" +typedef struct MITDB { + HDB db; /* Generic */ + int do_sync; /* MITDB-specific */ +} MITDB; + static void attr_to_flags(unsigned attr, HDBFlags *flags) { @@ -697,6 +702,18 @@ mdb_destroy(krb5_context context, HDB *db) return ret; } +static krb5_error_code +mdb_set_sync(krb5_context context, HDB *db, int on) +{ + MITDB *mdb = (MITDB *)db; + DB *d = (DB*)db->hdb_db; + + mdb->do_sync = on; + if (on) + return fsync((*d->fd)(d)); + return 0; +} + static krb5_error_code mdb_lock(krb5_context context, HDB *db, int operation) { @@ -861,6 +878,7 @@ static krb5_error_code mdb__put(krb5_context context, HDB *db, int replace, krb5_data key, krb5_data value) { + MITDB *mdb = (MITDB *)db; DB *d = (DB*)db->hdb_db; DBT k, v; int code; @@ -873,6 +891,11 @@ mdb__put(krb5_context context, HDB *db, int replace, if(code) return code; code = (*d->put)(d, &k, &v, replace ? 0 : R_NOOVERWRITE); + if (code == 0) { + code = mdb_set_sync(context, db, mdb->do_sync); + db->hdb_unlock(context, db); + return code; + } db->hdb_unlock(context, db); if(code < 0) { code = errno; @@ -880,16 +903,14 @@ mdb__put(krb5_context context, HDB *db, int replace, db->hdb_name, strerror(code)); return code; } - if(code == 1) { - krb5_clear_error_message(context); - return HDB_ERR_EXISTS; - } - return 0; + krb5_clear_error_message(context); + return HDB_ERR_EXISTS; } static krb5_error_code mdb__del(krb5_context context, HDB *db, krb5_data key) { + MITDB *mdb = (MITDB *)db; DB *d = (DB*)db->hdb_db; DBT k; krb5_error_code code; @@ -899,6 +920,11 @@ mdb__del(krb5_context context, HDB *db, krb5_data key) if(code) return code; code = (*d->del)(d, &k, 0); + if (code == 0) { + code = mdb_set_sync(context, db, mdb->do_sync); + db->hdb_unlock(context, db); + return code; + } db->hdb_unlock(context, db); if(code == 1) { code = errno; @@ -1090,8 +1116,9 @@ krb5_error_code hdb_mitdb_create(krb5_context context, HDB **db, const char *filename) { - *db = calloc(1, sizeof(**db)); - if (*db == NULL) { + MITDB **mdb (MITDB **)db; + *mdb = calloc(1, sizeof(**mdb)); + if (*mdb == NULL) { krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } @@ -1104,6 +1131,7 @@ hdb_mitdb_create(krb5_context context, HDB **db, krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } + (*mdb)->do_sync = 1; (*db)->hdb_master_key_set = 0; (*db)->hdb_openp = 0; (*db)->hdb_capability_flags = 0; @@ -1121,6 +1149,7 @@ hdb_mitdb_create(krb5_context context, HDB **db, (*db)->hdb__put = mdb__put; (*db)->hdb__del = mdb__del; (*db)->hdb_destroy = mdb_destroy; + (*db)->hdb_set_sync = mdb_set_sync; return 0; } diff --git a/lib/hdb/hdb-sqlite.c b/lib/hdb/hdb-sqlite.c index db4163bab..d5eb3f184 100644 --- a/lib/hdb/hdb-sqlite.c +++ b/lib/hdb/hdb-sqlite.c @@ -807,6 +807,15 @@ hdb_sqlite_destroy(krb5_context context, HDB *db) return ret ? ret : ret2; } +static krb5_error_code +hdb_sqlite_set_sync(krb5_context context, HDB *db, int on) +{ + return hdb_sqlite_exec_stmt(context, (hdb_sqlite_db*)(db->hdb_db), + on ? "PRAGMA main.synchronous = NORMAL" : + "PRAGMA main.synchronous = OFF", + HDB_ERR_UK_SERROR); +} + /* * Not sure if this is needed. */ @@ -1035,6 +1044,7 @@ hdb_sqlite_create(krb5_context context, HDB **db, const char *filename) (*db)->hdb_remove = hdb_sqlite_remove; (*db)->hdb_destroy = hdb_sqlite_destroy; (*db)->hdb_rename = hdb_sqlite_rename; + (*db)->hdb_set_sync = hdb_sqlite_set_sync; (*db)->hdb__get = NULL; (*db)->hdb__put = NULL; (*db)->hdb__del = NULL; diff --git a/lib/hdb/hdb.h b/lib/hdb/hdb.h index 892b8e598..7c6dfcf9d 100644 --- a/lib/hdb/hdb.h +++ b/lib/hdb/hdb.h @@ -271,9 +271,17 @@ typedef struct HDB { * Check if s4u2self is allowed from this client to this server */ krb5_error_code (*hdb_check_s4u2self)(krb5_context, struct HDB *, hdb_entry_ex *, krb5_const_principal); + + /** + * Enable/disable synchronous updates + * + * Calling this with 0 disables sync. Calling it with non-zero enables + * sync and does an fsync(). + */ + krb5_error_code (*hdb_set_sync)(krb5_context, struct HDB *, int); }HDB; -#define HDB_INTERFACE_VERSION 9 +#define HDB_INTERFACE_VERSION 10 struct hdb_method { int version;