📄 rep_backup.c
字号:
*/ if (rep->file_mpf != NULL) { ret = __memp_fclose(rep->file_mpf, 0); rep->file_mpf = NULL; if (ret != 0) goto err; } /* * 2. Close/reset the page database. */ ret = __db_close(rep->file_dbp, NULL, DB_NOSYNC); rep->file_dbp = NULL; if (ret != 0) goto err; /* * 3. Check if we have all file data. If so, request logs. */ __os_free(dbenv, rep->curinfo); if (++rep->curfile == rep->nfiles) { RPRINT(dbenv, rep, (dbenv, &mb, "FILEDONE: have %d files. RECOVER_LOG now", rep->nfiles)); /* * Move to REP_RECOVER_LOG state. * Request logs. */ __os_free(dbenv, rep->originfo); /* * We need to do a sync here so that any later opens * can find the file and file id. We need to do it * before we clear REP_F_RECOVER_PAGE so that we do not * try to flush the log. */ if ((ret = __memp_sync(dbenv, NULL)) != 0) goto err; F_CLR(rep, REP_F_RECOVER_PAGE); F_SET(rep, REP_F_RECOVER_LOG); memset(&dbt, 0, sizeof(dbt)); dbt.data = &rep->last_lsn; dbt.size = sizeof(rep->last_lsn); RPRINT(dbenv, rep, (dbenv, &mb, "FILEDONE: LOG_REQ from LSN [%lu][%lu] to [%lu][%lu]", (u_long)rep->first_lsn.file, (u_long)rep->first_lsn.offset, (u_long)rep->last_lsn.file, (u_long)rep->last_lsn.offset)); MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); if ((ret = __rep_log_setup(dbenv, rep)) != 0) goto err; (void)__rep_send_message(dbenv, eid, REP_LOG_REQ, &rep->first_lsn, &dbt, 0); MUTEX_LOCK(dbenv, db_rep->rep_mutexp); return (0); } /* * 4. If not, set curinfo to next file and request its pages. */ rep->finfo = rep->nextinfo; if ((ret = __rep_fileinfo_read(dbenv, rep->finfo, &rep->nextinfo, &rep->curinfo)) != 0) goto err; DB_ASSERT(rep->curinfo->pgno == 0); rep->ready_pg = 0; rep->npages = 0; rep->waiting_pg = PGNO_INVALID; rep->max_wait_pg = PGNO_INVALID; memset(&dbt, 0, sizeof(dbt)); RPRINT(dbenv, rep, (dbenv, &mb, "FILEDONE: Next file %d. Request pages 0 to %lu", rep->curinfo->filenum, (u_long)rep->curinfo->max_pgno)); dbt.data = rep->finfo; dbt.size = (u_int32_t)((u_int8_t *)rep->nextinfo - (u_int8_t *)rep->finfo); (void)__rep_send_message(dbenv, eid, REP_PAGE_REQ, NULL, &dbt, 0);err: return (ret);}/* * __rep_mpf_open - * Create and open the mpool file for a database. * Used by both master and client to bring files into mpool. */static int__rep_mpf_open(dbenv, mpfp, rfp) DB_ENV *dbenv; DB_MPOOLFILE **mpfp; __rep_fileinfo_args *rfp;{ DB db; int ret; if ((ret = __memp_fcreate(dbenv, mpfp)) != 0) return (ret); /* * We need a dbp to pass into to __db_dbenv_mpool. Set up * only the parts that it needs. */ db.type = rfp->type; db.pgsize = (u_int32_t)rfp->pgsize; memcpy(db.fileid, rfp->uid.data, DB_FILE_ID_LEN); db.flags = rfp->flags; db.mpf = *mpfp; db.dbenv = dbenv; if ((ret = __db_dbenv_mpool(&db, rfp->info.data, 0)) != 0) { (void)__memp_fclose(*mpfp, 0); *mpfp = NULL; } return (ret);}/* * __rep_pggap_req - * Request a page gap. Assumes the caller holds the rep_mutexp. * * PUBLIC: int __rep_pggap_req __P((DB_ENV *, REP *, __rep_fileinfo_args *, * PUBLIC: int)); */int__rep_pggap_req(dbenv, rep, reqfp, moregap) DB_ENV *dbenv; REP *rep; __rep_fileinfo_args *reqfp; int moregap;{ DBT max_pg_dbt; __rep_fileinfo_args *tmpfp; size_t len; int alloc, ret; ret = 0; alloc = 0; /* * There is a window where we have to set REP_RECOVER_PAGE when * we receive the update information to transition from getting * file information to getting page information. However, that * thread does release and then reacquire mutexes. So, we might * try re-requesting before the original thread can get curinfo * setup. If curinfo isn't set up there is nothing to do. */ if (rep->curinfo == NULL) return (0); if (reqfp == NULL) { if ((ret = __rep_finfo_alloc(dbenv, rep->curinfo, &tmpfp)) != 0) return (ret); alloc = 1; } else tmpfp = reqfp; /* * If we've never requested this page, then * request everything between it and the first * page we have. If we have requested this page * then only request this record, not the entire gap. */ memset(&max_pg_dbt, 0, sizeof(max_pg_dbt)); tmpfp->pgno = rep->ready_pg; max_pg_dbt.data = rep->finfo; max_pg_dbt.size = (u_int32_t)((u_int8_t *)rep->nextinfo - (u_int8_t *)rep->finfo); if (rep->max_wait_pg == PGNO_INVALID || moregap) { /* * Request the gap - set max to waiting_pg - 1 or if * there is no waiting_pg, just ask for one. */ if (rep->waiting_pg == PGNO_INVALID) { if (moregap) rep->max_wait_pg = rep->curinfo->max_pgno; else rep->max_wait_pg = rep->ready_pg; } else rep->max_wait_pg = rep->waiting_pg - 1; tmpfp->max_pgno = rep->max_wait_pg; } else { /* * Request 1 page - set max to ready_pg. */ rep->max_wait_pg = rep->ready_pg; tmpfp->max_pgno = rep->ready_pg; } if (rep->master_id != DB_EID_INVALID) { rep->stat.st_pg_requested++; /* * We need to request the pages, but we need to get the * new info into rep->finfo. Assert that the sizes never * change. The only thing this should do is change * the pgno field. Everything else remains the same. */ ret = __rep_fileinfo_buf(rep->finfo, max_pg_dbt.size, &len, tmpfp->pgsize, tmpfp->pgno, tmpfp->max_pgno, tmpfp->filenum, tmpfp->id, tmpfp->type, tmpfp->flags, &tmpfp->uid, &tmpfp->info); DB_ASSERT(len == max_pg_dbt.size); (void)__rep_send_message(dbenv, rep->master_id, REP_PAGE_REQ, NULL, &max_pg_dbt, 0); } else (void)__rep_send_message(dbenv, DB_EID_BROADCAST, REP_MASTER_REQ, NULL, NULL, 0); if (alloc) __os_free(dbenv, tmpfp); return (ret);}/* * __rep_loggap_req - * Request a log gap. Assumes the caller holds the db_mutexp. * * PUBLIC: void __rep_loggap_req __P((DB_ENV *, REP *, DB_LSN *, int)); */void__rep_loggap_req(dbenv, rep, lsnp, moregap) DB_ENV *dbenv; REP *rep; DB_LSN *lsnp; int moregap;{ DB_LOG *dblp; DBT max_lsn_dbt, *max_lsn_dbtp; DB_LSN next_lsn; LOG *lp; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; R_LOCK(dbenv, &dblp->reginfo); next_lsn = lp->lsn; R_UNLOCK(dbenv, &dblp->reginfo); if (moregap || (lsnp != NULL && (log_compare(lsnp, &lp->max_wait_lsn) == 0 || IS_ZERO_LSN(lp->max_wait_lsn)))) { /* * We need to ask for the gap. Either we never asked * for records before, or we asked for a single record * and received it. */ lp->max_wait_lsn = lp->waiting_lsn; memset(&max_lsn_dbt, 0, sizeof(max_lsn_dbt)); max_lsn_dbt.data = &lp->waiting_lsn; max_lsn_dbt.size = sizeof(lp->waiting_lsn); max_lsn_dbtp = &max_lsn_dbt; } else { max_lsn_dbtp = NULL; lp->max_wait_lsn = next_lsn; } if (rep->master_id != DB_EID_INVALID) { rep->stat.st_log_requested++; (void)__rep_send_message(dbenv, rep->master_id, REP_LOG_REQ, &next_lsn, max_lsn_dbtp, 0); } else (void)__rep_send_message(dbenv, DB_EID_BROADCAST, REP_MASTER_REQ, NULL, NULL, 0); return;}/* * __rep_finfo_alloc - * Allocate and initialize a fileinfo structure. * * PUBLIC: int __rep_finfo_alloc __P((DB_ENV *, __rep_fileinfo_args *, * PUBLIC: __rep_fileinfo_args **)); */int__rep_finfo_alloc(dbenv, rfpsrc, rfpp) DB_ENV *dbenv; __rep_fileinfo_args *rfpsrc, **rfpp;{ size_t size; int ret; size = sizeof(__rep_fileinfo_args) + rfpsrc->uid.size + rfpsrc->info.size; if ((ret = __os_malloc(dbenv, size, rfpp)) != 0) return (ret); memcpy(*rfpp, rfpsrc, size); return (ret);}/* * __rep_log_setup - * We know our first LSN and need to reset the log subsystem * to get our logs set up for the proper file. */static int__rep_log_setup(dbenv, rep) DB_ENV *dbenv; REP *rep;{ DB_LOG *dblp; DB_LSN lsn; u_int32_t fnum; int ret; char *name; dblp = dbenv->lg_handle; /* * Set up the log starting at the file number of the first LSN we * need to get from the master. */ if ((ret = __log_newfile(dblp, &lsn, rep->first_lsn.file)) == 0) { /* * We do know we want to start this client's log at * log file 'first_lsn.file'. So we want to forcibly * remove any log files earlier than that number. * We don't know what might be in any earlier log files * so we cannot just use __log_autoremove. */ for (fnum = 1; fnum < rep->first_lsn.file; fnum++) { if ((ret = __log_name(dblp, fnum, &name, NULL, 0)) != 0) goto err; (void)__os_unlink(dbenv, name); __os_free(dbenv, name); } }err: return (ret);}/* * __rep_queue_filedone - * Determine if we're really done getting the pages for a queue file. * Queue is handled in several steps. * 1. First we get the meta page only. * 2. We use the meta-page information to figure out first and last * page numbers (and if queue wraps, first can be > last. * 3. If first < last, we do a REP_PAGE_REQ for all pages. * 4. If first > last, we REP_PAGE_REQ from first -> max page number. * Then we'll ask for page 1 -> last. * * This function can return several things: * DB_REP_PAGEDONE - if we're done with this file. * 0 - if we're not doen with this file. * error - if we get an error doing some operations. * * This function will open a dbp handle to the queue file. This is needed * by most of the QAM macros. We'll open it on the first pass through * here and we'll close it whenever we decide we're done. */static int__rep_queue_filedone(dbenv, rep, rfp) DB_ENV *dbenv; REP *rep; __rep_fileinfo_args *rfp;{#ifndef HAVE_QUEUE COMPQUIET(rep, NULL); COMPQUIET(rfp, NULL); return (__db_no_queue_am(dbenv));#else db_pgno_t first, last; u_int32_t flags; int empty, ret, t_ret;#ifdef DIAGNOSTIC DB_MSGBUF mb;#endif ret = 0; if (rep->queue_dbp == NULL) { /* * We need to do a sync here so that the open * can find the file and file id. */ if ((ret = __memp_sync(dbenv, NULL)) != 0) goto out; if ((ret = db_create(&rep->queue_dbp, dbenv, DB_REP_CREATE)) != 0) goto out; flags = DB_NO_AUTO_COMMIT | (F_ISSET(dbenv, DB_ENV_THREAD) ? DB_THREAD : 0); if ((ret = __db_open(rep->queue_dbp, NULL, rfp->info.data, NULL, DB_QUEUE, flags, 0, PGNO_BASE_MD)) != 0) goto out; } if ((ret = __queue_pageinfo(rep->queue_dbp, &first, &last, &empty, 0, 0)) != 0) goto out; RPRINT(dbenv, rep, (dbenv, &mb, "Queue fileinfo: first %lu, last %lu, empty %d", (u_long)first, (u_long)last, empty)); /* * We can be at the end of 3 possible states. * 1. We have received the meta-page and now need to get the * rest of the pages in the database. * 2. We have received from first -> max_pgno. We might be done, * or we might need to ask for wrapped pages. * 3. We have received all pages in the file. We're done. */ if (rfp->max_pgno == 0) { /* * We have just received the meta page. Set up the next * pages to ask for and check if the file is empty. */ if (empty) goto out; if (first > last) { rfp->max_pgno = QAM_RECNO_PAGE(rep->queue_dbp, UINT32_MAX); } else rfp->max_pgno = last; RPRINT(dbenv, rep, (dbenv, &mb, "Queue fileinfo: First req: first %lu, last %lu", (u_long)first, (u_long)rfp->max_pgno)); goto req; } else if (rfp->max_pgno != last) { /* * If max_pgno != last that means we're dealing with a * wrapped situation. Request next batch of pages. * Set npages to 1 because we already have page 0, the * meta-page, now we need pages 1-max_pgno. */ first = 1; rfp->max_pgno = last; RPRINT(dbenv, rep, (dbenv, &mb, "Queue fileinfo: Wrap req: first %lu, last %lu", (u_long)first, (u_long)last));req: /* * Since we're simulating a "gap" to resend new PAGE_REQ * for this file, we need to set waiting page to last + 1 * so that we'll ask for all from ready_pg -> last. */ rep->npages = first; rep->ready_pg = first; rep->waiting_pg = rfp->max_pgno + 1; rep->max_wait_pg = PGNO_INVALID; ret = __rep_pggap_req(dbenv, rep, rfp, 0); return (ret); } /* * max_pgno == last * If we get here, we have all the pages we need. * Close the dbp and return. */out: if (rep->queue_dbp != NULL && (t_ret = __db_close(rep->queue_dbp, NULL, DB_NOSYNC)) != 0 && ret == 0) ret = t_ret; rep->queue_dbp = NULL; if (ret == 0) ret = DB_REP_PAGEDONE; return (ret);#endif}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -