summaryrefslogtreecommitdiff
path: root/src/rep/rep_region.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rep/rep_region.c')
-rw-r--r--src/rep/rep_region.c164
1 files changed, 157 insertions, 7 deletions
diff --git a/src/rep/rep_region.c b/src/rep/rep_region.c
index f1d69dff..72372bff 100644
--- a/src/rep/rep_region.c
+++ b/src/rep/rep_region.c
@@ -1,7 +1,7 @@
/*-
* See the file LICENSE for redistribution information.
*
- * Copyright (c) 2001, 2012 Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2015 Oracle and/or its affiliates. All rights reserved.
*
* $Id$
*/
@@ -14,6 +14,8 @@
static int __rep_egen_init __P((ENV *, REP *));
static int __rep_gen_init __P((ENV *, REP *));
+static int __rep_view_init __P((ENV *, REP *));
+static int __rep_viewfile_exists __P((ENV *, int *));
/*
* __rep_open --
@@ -29,7 +31,7 @@ __rep_open(env)
REGENV *renv;
REGINFO *infop;
REP *rep;
- int i, ret;
+ int i, ret, view;
char *p;
char fname[sizeof(REP_DIAGNAME) + 3];
@@ -37,10 +39,15 @@ __rep_open(env)
infop = env->reginfo;
renv = infop->primary;
ret = 0;
+ view = 0;
DB_ASSERT(env, DBREP_DIAG_FILES < 100);
if (renv->rep_off == INVALID_ROFF) {
- /* Must create the region. */
+ /*
+ * Must create the region. This environment either is being
+ * created for the first time or has just had its regions
+ * cleared by a recovery.
+ */
if ((ret = __env_alloc(infop, sizeof(REP), &rep)) != 0)
return (ret);
memset(rep, 0, sizeof(*rep));
@@ -108,6 +115,23 @@ __rep_open(env)
return (ret);
if ((ret = __rep_egen_init(env, rep)) != 0)
return (ret);
+ /*
+ * Determine if this is a view site or not. It is a view
+ * if the callback is set. If the site was a view in the
+ * past, we mark it as a view, but will check consistency
+ * later when starting replication.
+ */
+ if (db_rep->partial != NULL) {
+ rep->stat.st_view = 1;
+ if ((ret = __rep_view_init(env, rep)) != 0)
+ return (ret);
+ } else {
+ if ((ret = __rep_viewfile_exists(env, &view)) != 0)
+ return (ret);
+ if (view)
+ rep->stat.st_view = 1;
+ }
+
rep->gbytes = db_rep->gbytes;
rep->bytes = db_rep->bytes;
rep->request_gap = db_rep->request_gap;
@@ -157,6 +181,32 @@ __rep_open(env)
"process joining the environment"));
return (EINVAL);
}
+ /*
+ * If we are joining an existing environment and we
+ * have a view callback set, then the environment must
+ * already be a view. If not, error.
+ *
+ * The other mismatch is not an error here (no callback
+ * set, but environment is a view) because we may be a
+ * rep unaware process such as db_stat and that is allowed
+ * to proceed. There is additional checking in other rep
+ * functions like rep_start to confirm consistency before
+ * using replication.
+ */
+ if (db_rep->partial != NULL) {
+ if ((ret = __rep_viewfile_exists(env, &view)) != 0)
+ return (ret);
+ /*
+ * If there is a callback, and we are not in-memory,
+ * there better be a view system file too.
+ */
+ if (view == 0 && !FLD_ISSET(rep->config, REP_C_INMEM)) {
+ __db_errx(env, DB_STR("3688",
+ "Application environment and view mismatch "
+ "joining the environment"));
+ return (EINVAL);
+ }
+ }
#ifdef HAVE_REPLICATION_THREADS
if ((ret = __repmgr_join(env, rep)) != 0)
return (ret);
@@ -506,9 +556,8 @@ __rep_write_egen(env, rep, egen)
* If running in-memory replication, return without any file
* operations.
*/
- if (FLD_ISSET(rep->config, REP_C_INMEM)) {
+ if (FLD_ISSET(rep->config, REP_C_INMEM))
return (0);
- }
if ((ret = __db_appname(env,
DB_APP_META, REP_EGENNAME, NULL, &p)) != 0)
@@ -591,9 +640,8 @@ __rep_write_gen(env, rep, gen)
* If running in-memory replication, return without any file
* operations.
*/
- if (FLD_ISSET(rep->config, REP_C_INMEM)) {
+ if (FLD_ISSET(rep->config, REP_C_INMEM))
return (0);
- }
if ((ret = __db_appname(env,
DB_APP_META, REP_GENNAME, NULL, &p)) != 0)
@@ -608,3 +656,105 @@ __rep_write_gen(env, rep, gen)
__os_free(env, p);
return (ret);
}
+
+/*
+ * __rep_view_init --
+ * Initialize the permanent view file to know this site is a view
+ * forever. The existence of the file is the record.
+ */
+static int
+__rep_view_init(env, rep)
+ ENV *env;
+ REP *rep;
+{
+ DB_FH *fhp;
+ int ret;
+ char *p;
+
+ /*
+ * If running in-memory replication, return without any file
+ * operations.
+ */
+ if (FLD_ISSET(rep->config, REP_C_INMEM))
+ return (0);
+
+ if ((ret = __db_appname(env,
+ DB_APP_META, REPVIEW, NULL, &p)) != 0)
+ return (ret);
+
+ /*
+ * If the file doesn't exist, create it. We just want to open
+ * and close the file. It doesn't have any content.
+ * If the file already exists, there is nothing else to do.
+ */
+ if (__os_exists(env, p, NULL) != 0) {
+ RPRINT(env, (env, DB_VERB_REP_MISC, "View init: Create %s", p));
+ if ((ret = __os_open(env, p, 0,
+ DB_OSO_CREATE | DB_OSO_TRUNC, DB_MODE_600, &fhp)) != 0)
+ goto out;
+ (void)__os_closehandle(env, fhp);
+ }
+out: __os_free(env, p);
+ return (ret);
+}
+
+/*
+ * __rep_check_view --
+ * Check consistency between the view file and the db_rep handle.
+ *
+ * PUBLIC: int __rep_check_view __P((ENV *));
+ */
+int
+__rep_check_view(env)
+ ENV *env;
+{
+ DB_REP *db_rep;
+ REP *rep;
+ int exist, ret;
+
+ db_rep = env->rep_handle;
+ rep = db_rep->region;
+ ret = 0;
+
+ /*
+ * If running in-memory replication, check without any file
+ * operations. We can only check what exists in the region,
+ * which is the st_view field from a previous open.
+ */
+ if (FLD_ISSET(rep->config, REP_C_INMEM))
+ exist = (int)rep->stat.st_view;
+ else if ((ret = __rep_viewfile_exists(env, &exist)) != 0)
+ return (ret);
+
+ RPRINT(env, (env, DB_VERB_REP_MISC, "Check view. Exist %d, cb %d",
+ exist, (db_rep->partial != NULL)));
+ /*
+ * If view file exists, a partial function must be set.
+ * If view file does not exist, a partial function must not be set.
+ */
+ if ((exist == 0 && db_rep->partial != NULL) ||
+ (exist == 1 && db_rep->partial == NULL))
+ ret = EINVAL;
+ return (ret);
+}
+
+static int
+__rep_viewfile_exists(env, existp)
+ ENV *env;
+ int *existp;
+{
+ char *p;
+ int ret;
+
+ *existp = 0;
+ if ((ret = __db_appname(env,
+ DB_APP_META, REPVIEW, NULL, &p)) != 0)
+ return (ret);
+
+ if (__os_exists(env, p, NULL) == 0)
+ *existp = 1;
+
+ __os_free(env, p);
+ return (ret);
+
+}