static void run_expiry() { DBC *dbcp; int rc; time_t now; unsigned int count = 0; /* Cursor operations can hold several locks and therefore deadlock so don't run expiry if deadlock detection does not work http://www.oracle.com/technology/documentation/berkeley-db/db/ref/lock/notxn.html */ if (db == 0 || deadlock_detect == 0) return; if (time(&now) == (time_t)-1) { syslog(LOG_ERR, "time failed during run_expiry"); return; } muffle_error++; if (rc = db->cursor(db, 0, &dbcp, 0)) log_db_error("db->cursor failed during expiry run", rc); else { DBT key = { 0 }; while ((rc = dbcp->c_get(dbcp, &key, &dbdata, DB_NEXT | DB_RMW)) == 0) { time_t ref_time; double age_max, age; if (triplet_data.pass_count) { ref_time = triplet_data.access_time; age_max = pass_max_idle; } else { ref_time = triplet_data.create_time; age_max = bloc_max_idle; } age = difftime(now, ref_time); if (age > age_max) { if (opt_verbose) syslog(LOG_INFO, "Expiring %s %s after %.0f seconds idle", key.data, triplet_data.pass_count ? "pass" : "block", age); if (rc = dbcp->c_del(dbcp, 0)) log_db_error("dbcp->c_del failed", rc); else count++; } } if (rc == DB_LOCK_DEADLOCK) syslog(LOG_DEBUG, "skipping concurrent expiry avoids " "deadlocks and unnecessary work"); else if (rc != DB_NOTFOUND) log_db_error("dbcp->c_get failed", rc); if (rc = dbcp->c_close(dbcp)) log_db_error("dbcp->c_close failed", rc); } muffle_error--; if (count) syslog(LOG_NOTICE, "Expired %u triplets", count); }
static void get_grey_data(DB *db, DB_TXN *txn) { int rc; rc = db->get(db, txn, &dbkey, &dbdata, 0); if (rc == DB_NOTFOUND) { touch_data(); build_data(); } else if (rc) { log_db_error("get failed", rc); jmperr("get failed"); } else { time_t ref_time; double age_max; if (triplet_data.pass_count) { ref_time = triplet_data.access_time; age_max = pass_max_idle; } else { ref_time = triplet_data.create_time; age_max = bloc_max_idle; } touch_data(); /* Expire IDLE records */ if (difftime(triplet_data.access_time, ref_time) > age_max) build_data(); } }
static int call_db(int err, const char *msg) { if (err) log_db_error(msg, err); return err; }
static int prepare_db() { int rc; rc = db_create(&db, dbenv, 0); if (rc) log_db_error("db_create", rc); else { rc = db_open(db, DB_FILE_NAME, NULL, DB_BTREE, DB_CREATE, 0644); if (rc) { log_db_error("db->open", rc); db->close(db, 0); db = 0; } } return rc; }
static int put_grey_data() { int rc; rc = db->put(db, NULL, &dbkey, &dbdata, 0); if (rc) log_db_error("put", rc); return rc; }
static void cleanup() { int rc; if (dbkey.data) free(dbkey.data); if (db) { rc = db->close(db, 0); if (rc) log_db_error("DB close", rc); } rc = db_create(&db, dbenv, 0); if (!rc) if (! db->remove(db, "tls_stats.db", 0, 0)) syslog(LOG_NOTICE, "Unused database tls_stats.db removed"); db = 0; if (dbenv) { rc = dbenv->close(dbenv, 0); dbenv = 0; if (rc) log_db_error("DB_ENV close", rc); } policy_cleanup(); }
static int prepare_env() { int rc; rc = db_env_create(&dbenv, 0); if (rc) log_db_error("db_env_create", rc); else { dbenv->set_errcall(dbenv, db_errcall_fcn); rc = dbenv->set_lk_detect(dbenv, DB_LOCK_YOUNGEST); if (rc) log_db_error("dbenv->set_lk_detect DB_LOCK_YOUNGEST, expired triplets will not be deleted", rc); else deadlock_detect = 1; rc = dbenv->open(dbenv, db_home, DB_INIT_LOCK | DB_INIT_MPOOL | DB_CREATE, 0); if (rc) { log_db_error("dbenv->open", rc); dbenv->close(dbenv, 0); dbenv = 0; } } return rc; }
static void run_expiry() { DB_ENV *dbenv; DB *db; DB_TXN *txn; DBC *dbcp; int rc; time_t now; DBT key = { 0 }; unsigned int count = 0; if (exit_requested) return; /* Cursor operations can hold several locks and therefore deadlock so don't run expiry if deadlock detection does not work http://docs.oracle.com/cd/E17076_02/html/programmer_reference/lock_notxn.html */ rc = get_db(&db, 0); assert(! rc); if (db == 0 || deadlock_detect == 0) return; rc = get_dbenv(&dbenv, 0); assert(! rc && dbenv); if (time(&now) == (time_t)-1) { syslog(LOG_ERR, "time failed during run_expiry"); return; } muffle_error++; rc = dbenv->txn_begin(dbenv, NULL, &txn, DB_TXN_NOWAIT); if (rc) { if (rc == DB_LOCK_DEADLOCK) syslog(LOG_DEBUG, "skipping concurrent expiry avoids " "deadlocks and unnecessary work"); else log_db_error("txn_begin failed during run_expiry", rc); goto out; } #if DB_VERSION_MAJOR >= 5 call_db(txn->set_priority(txn, 50), "TXN->set_priority"); #endif rc = call_db(db->cursor(db, txn, &dbcp, 0), "db->cursor failed during expiry run"); if (rc) goto txn_fail; while ((rc = dbcp->c_get(dbcp, &key, &dbdata, DB_NEXT | DB_RMW)) == 0) { time_t ref_time; double age_max, age; if (triplet_data.pass_count) { ref_time = triplet_data.access_time; age_max = pass_max_idle; } else { ref_time = triplet_data.create_time; age_max = bloc_max_idle; } age = difftime(now, ref_time); if (age > age_max) { if (opt_verbose) { syslog(LOG_INFO, "Expiring %s %s after %.0f seconds idle", db_key_ntop(key.data), triplet_data.pass_count ? "pass" : "block", age); } rc = call_db(dbcp->c_del(dbcp, 0), "dbcp->c_del failed"); if (rc) goto cursor_fail; count++; } if (exit_requested) break; } if (rc && rc != DB_NOTFOUND) { if (rc == DB_LOCK_DEADLOCK) syslog(LOG_NOTICE, "Aborting concurrent expiry due to deadlock"); else log_db_error("dbcp->c_get failed", rc); goto cursor_fail; } if (call_db(dbcp->c_close(dbcp), "dbcp->c_close failed")) goto txn_fail; call_db(txn->commit(txn, 0), "commit failed in run_expiry"); if (count) syslog(LOG_NOTICE, "Expired %u triplets", count); goto out; cursor_fail: call_db(dbcp->c_close(dbcp), "dbcp->c_close failed"); txn_fail: call_db(txn->abort(txn), "failed to abort"); out: muffle_error--; return; }