int candidate_validate(clicon_handle h, char *candidate, char *running) { struct dbdiff df; dbdep_dd_t *ddvec = NULL; int nvec; int retval = -1; struct stat sb; void *firsterr = NULL; /* Sanity checks that databases exists. */ if (stat(running, &sb) < 0){ clicon_err(OE_DB, errno, "%s", running); goto done; } if (stat(candidate, &sb) < 0){ clicon_err(OE_DB, errno, "%s", candidate); goto done; } memset(&df, 0, sizeof(df)); /* Find the differences between the two databases and store it in df vector. */ if (db_diff(running, candidate, __FUNCTION__, clicon_dbspec_key(h), &df ) < 0) goto done; /* 1. Get commit processing dbdiff vector (df): one entry per key that changed. changes are registered as if they exist in the 1st(candidate) or 2nd(running) dbs. */ if (dbdep_commitvec(h, &df, &nvec, &ddvec) < 0) goto done; /* 2. Call plugin pre-commit hooks */ if (plugin_begin_hooks(h, candidate) < 0) goto done; /* call generic cv_validate() on all new or changed keys. */ if (generic_validate(h, candidate, &df) < 0) goto done; /* user-defined callbacks */ if (validate_db(h, nvec, ddvec, candidate) < 0) goto done; /* Call plugin post-commit hooks */ if (plugin_complete_hooks(h, candidate) < 0) goto done; retval = 0; done: if (retval < 0) /* Call plugin fail-commit hooks */ plugin_abort_hooks(h, candidate); if (ddvec) free(ddvec); unchunk_group(__FUNCTION__); if (firsterr) clicon_err_restore(firsterr); return retval; }
int main(int argc, char **argv) { int i = 0; int diff_state = 0; struct bu_ptbl results; struct db_i *dbip1 = DBI_NULL; struct db_i *dbip2 = DBI_NULL; /*struct bu_vls diff_log = BU_VLS_INIT_ZERO;*/ struct bn_tol *diff_tol; BU_GET(diff_tol, struct bn_tol); diff_tol->dist = BN_TOL_DIST; BU_PTBL_INIT(&results); if (argc != 3) { bu_log("Error - please specify two .g files\n"); bu_exit(EXIT_FAILURE, NULL); } if (!bu_file_exists(argv[1], NULL)) { bu_exit(1, "Cannot stat file %s\n", argv[1]); } if (!bu_file_exists(argv[2], NULL)) { bu_exit(1, "Cannot stat file %s\n", argv[2]); } if ((dbip1 = db_open(argv[1], DB_OPEN_READONLY)) == DBI_NULL) { bu_exit(1, "Cannot open geometry database file %s\n", argv[1]); } RT_CK_DBI(dbip1); if (db_dirbuild(dbip1) < 0) { db_close(dbip1); bu_exit(1, "db_dirbuild failed on geometry database file %s\n", argv[1]); } /* Reset the material head so we don't get warnings when the global * is overwritten. This will go away when material_head ceases to * be a librt global.*/ rt_new_material_head(MATER_NULL); if ((dbip2 = db_open(argv[2], DB_OPEN_READONLY)) == DBI_NULL) { bu_exit(1, "Cannot open geometry database file %s\n", argv[2]); } RT_CK_DBI(dbip2); if (db_dirbuild(dbip2) < 0) { db_close(dbip1); db_close(dbip2); bu_exit(1, "db_dirbuild failed on geometry database file %s\n", argv[1]); } diff_state = db_diff(dbip1, dbip2, diff_tol, DB_COMPARE_ALL, &results); if (diff_state == DIFF_UNCHANGED) { bu_log("No differences found.\n"); } else { print_diff_summary(&results); } for (i = 0; i < (int)BU_PTBL_LEN(&results); i++) { struct diff_result *result = (struct diff_result *)BU_PTBL_GET(&results, i); diff_free_result(result); } bu_ptbl_free(&results); BU_PUT(diff_tol, struct bn_tol); db_close(dbip1); db_close(dbip2); return 0; }
/* * candidate_commit * Do a diff between candidate and running, and then call plugins to * commit the changes. * The code reverts changes if the commit fails. But if the revert * fails, we just ignore the errors and proceed. Maybe we should * do something more drastic? * Arguments: * running: The current database. The state of the router corresponds * to these values. Also called db1. * candidate: The candidate database. We are aiming to put the router in this * state. Also called db2. (_dp) [op, callback] (dpe_) +---------------+ +---------------+ | dbdep_t |--> | dbdep_ent_t | [key, var] +---------------+ +---------------+ ^ Database dependency description from dbdep_commit() | +---------------+* |dd_dep | dbdep_dd_t |-----+ +---------------+ |dd_dbdiff (dd_) | v +---------------+ +---------------+ | dbdiff |---->| dbdiff_ent | [key1, key2, add/change/rm] (dfe_) +---------------+ +---------------+ (df_) from dbdiff(), (dfe_) */ int candidate_commit(clicon_handle h, char *candidate, char *running) { struct dbdiff df; dbdep_t *dp; struct dbdiff_ent *dfe; dbdep_dd_t *ddvec = NULL; dbdep_dd_t *dd; int nvec; int retval = -1; int i, j; int failed = 0; struct stat sb; void *firsterr = NULL; /* Sanity checks that databases exists. */ if (stat(running, &sb) < 0){ clicon_err(OE_DB, errno, "%s", running); goto done; } if (stat(candidate, &sb) < 0){ clicon_err(OE_DB, errno, "%s", candidate); goto done; } memset(&df, 0, sizeof(df)); /* Find the differences between the two databases and store it in dd vector. */ if (db_diff(running, candidate, __FUNCTION__, clicon_dbspec_key(h), &df ) < 0) goto done; /* 1. Get commit processing dbdiff vector: one entry per key that changed. changes are registered as if they exist in the 1st(candidate) or 2nd(running) dbs. */ if (dbdep_commitvec(h, &df, &nvec, &ddvec) < 0) goto done; /* 2. Call plugin pre-commit hooks */ if (plugin_begin_hooks(h, candidate) < 0) goto done; /* call generic cv_validate() on all new or changed keys. */ if (generic_validate(h, candidate, &df) < 0) goto done; /* user-defined callbacks */ if (validate_db(h, nvec, ddvec, candidate) < 0) goto done; /* Call plugin post-commit hooks */ if (plugin_complete_hooks(h, candidate) < 0) goto done; /* Now follows commit rules in order. * 4. For all keys that are in candidate, delete key (from running). */ for (i = nvec-1; i >= 0; i--){ dd = &ddvec[i]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_FIRST && plugin_modify_key_value(h, running, /* db */ dfe->dfe_key1, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_DELETE, /* operation */ dp /* callback(arg) */ ) < 0){ firsterr = clicon_err_save(); /* save this error */ break; } } /* 5. Failed deletion of running, add the key value back (from running) */ if (i >= 0){ /* failed */ for (j=i+1; j<nvec; j++){ /* revert in opposite order */ dd = &ddvec[j]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_FIRST && plugin_modify_key_value(h, running, /* db */ dfe->dfe_key1, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_SET, /* operation */ dp /* callback(arg) */ ) < 0) continue; /* ignore errors or signal major setback ? */ } goto done; } /* 6. Set keys (from candidate) */ for (i=0; i < nvec; i++){ dd = &ddvec[i]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_SECOND && plugin_modify_key_value(h, candidate, /* db */ dfe->dfe_key2, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_SET, /* operation */ dp /* callback(arg) */ ) < 0){ firsterr = clicon_err_save(); /* save this error */ failed++; break; } } if (!failed) if (file_cp(candidate, running) < 0){ clicon_err(OE_UNIX, errno, "file_cp"); failed++; } /* 7. Failed setting keys in running, first remove the keys set */ if (failed){ /* failed */ for (j=i-1; j>=0; j--){ /* revert in opposite order */ dd = &ddvec[j]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_SECOND && plugin_modify_key_value(h, candidate, /* db */ dfe->dfe_key2, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_DELETE, /* operation */ dp /* callback(arg) */ ) < 0) continue; /* ignore errors or signal major setback ? */ } /* 7. Set back original running values */ for (j=0; j < nvec; j++){ /* revert in opposite order */ dd = &ddvec[j]; dfe = dd->dd_dbdiff; /* key1/key2/op */ dp = dd->dd_dep; /* op, callback, arg */ if (dp->dp_type & TRANS_CB_COMMIT && dfe->dfe_op & DBDIFF_OP_FIRST && plugin_modify_key_value(h, running, /* db */ dfe->dfe_key1, /* key */ TRANS_CB_COMMIT, /* commit|validate */ LV_SET, /* operation */ dp /* callback(arg) */ ) < 0) continue; /* ignore errors or signal major setback ? */ } goto done; } /* Copy running back to candidate in case end functions triggered updates in running */ /* XXX: check for errors */ file_cp(running, candidate); /* Call plugin post-commit hooks */ plugin_end_hooks(h, candidate); retval = 0; done: if (retval < 0) /* Call plugin fail-commit hooks */ plugin_abort_hooks(h, candidate); if (ddvec) free(ddvec); unchunk_group(__FUNCTION__); if (firsterr) clicon_err_restore(firsterr); return retval; }