📄 rep_backup.c
字号:
rep->stat.st_pg_duplicated++; ret = 0; goto err_nolock; } if (ret != 0) goto err_nolock; RPRINT(dbenv, rep, (dbenv, &mb, "PAGE: Write page %lu into mpool", (u_long)msgfp->pgno)); MUTEX_LOCK(dbenv, db_rep->rep_mutexp); /* * We put the page in the database file itself. */ ret = __rep_write_page(dbenv, rep, msgfp); if (ret != 0) { /* * We got an error storing the page, therefore, we need * remove this page marker from the page database too. * !!! * I'm ignoring errors from the delete because we want to * return the original error. If we cannot write the page * and we cannot delete the item we just put, what should * we do? Panic the env and return DB_RUNRECOVERY? */ (void)__db_del(rep->file_dbp, NULL, &key, 0); goto err; } rep->stat.st_pg_records++; rep->npages++; /* * Now check the LSN on the page and save it if it is later * than the one we have. */ if (log_compare(&rp->lsn, &rep->last_lsn) > 0) rep->last_lsn = rp->lsn; /* * We've successfully written the page. Now we need to see if * we're done with this file. __rep_filedone will check if we * have all the pages expected and if so, set up for the next * file and send out a page request for the next file's pages. */ ret = __rep_filedone(dbenv, eid, rep, msgfp, rp->rectype);err: MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp);err_nolock: __os_free(dbenv, msgfp); return (ret);}/* * __rep_page_fail * Process a page fail message. * * PUBLIC: int __rep_page_fail __P((DB_ENV *, int, DBT *)); */int__rep_page_fail(dbenv, eid, rec) DB_ENV *dbenv; int eid; DBT *rec;{ DB_REP *db_rep; REP *rep; __rep_fileinfo_args *msgfp, *rfp; int ret; void *next;#ifdef DIAGNOSTIC DB_MSGBUF mb;#endif ret = 0; db_rep = dbenv->rep_handle; rep = db_rep->region; MUTEX_LOCK(dbenv, db_rep->rep_mutexp); if (!F_ISSET(rep, REP_F_RECOVER_PAGE)) { MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); return (0); } if ((ret = __rep_fileinfo_read(dbenv, rec->data, &next, &msgfp)) != 0) { MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); return (ret); } /* * Check if this page is from the file we're expecting. * This may be an old or delayed page message. */ /* * !!! * If we allow dbrename/dbremove on the master while a client * is updating, then we'd have to verify the file's uid here too. */ if (msgfp->filenum != rep->curfile) { RPRINT(dbenv, rep, (dbenv, &mb, "Msg file %d != curfile %d", msgfp->filenum, rep->curfile)); MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); return (0); } rfp = rep->curinfo; if (rfp->type != DB_QUEUE) --rfp->max_pgno; else { /* * Queue is special. Pages at the beginning of the queue * may disappear, as well as at the end. Use msgfp->pgno * to adjust accordingly. */ RPRINT(dbenv, rep, (dbenv, &mb, "page_fail: BEFORE page %lu failed. ready %lu, max %lu, npages %d", (u_long)msgfp->pgno, (u_long)rep->ready_pg, (u_long)rfp->max_pgno, rep->npages)); if (msgfp->pgno == rfp->max_pgno) --rfp->max_pgno; if (msgfp->pgno >= rep->ready_pg) { rep->ready_pg = msgfp->pgno + 1; rep->npages = rep->ready_pg; } RPRINT(dbenv, rep, (dbenv, &mb, "page_fail: AFTER page %lu failed. ready %lu, max %lu, npages %d", (u_long)msgfp->pgno, (u_long)rep->ready_pg, (u_long)rfp->max_pgno, rep->npages)); } /* * We've lowered the number of pages expected. It is possible that * this was the last page we were expecting. Now we need to see if * we're done with this file. __rep_filedone will check if we have * all the pages expected and if so, set up for the next file and * send out a page request for the next file's pages. */ ret = __rep_filedone(dbenv, eid, rep, msgfp, REP_PAGE_FAIL); MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); return (ret);}/* * __rep_write_page - * Write this page into a database. */static int__rep_write_page(dbenv, rep, msgfp) DB_ENV *dbenv; REP *rep; __rep_fileinfo_args *msgfp;{ __rep_fileinfo_args *rfp; DB_FH *rfh; int ret; void *dst; char *real_name; real_name = NULL; /* * If this is the first page we're putting in this database, we need * to create the mpool file. Otherwise call memp_fget to create the * page in mpool. Then copy the data to the page, and memp_fput the * page to give it back to mpool. * * We need to create the file, removing any existing file and associate * the correct file ID with the new one. */ if (rep->file_mpf == NULL) { rfp = rep->curinfo; if (!F_ISSET(rfp, DB_AM_INMEM)) { if ((ret = __db_appname(dbenv, DB_APP_DATA, rfp->info.data, 0, NULL, &real_name)) != 0) goto err; /* * Calling memp_nameop will both purge any matching * fileid from mpool and unlink it on disk. */ if ((ret = __memp_nameop(dbenv, rfp->uid.data, NULL, real_name, NULL)) != 0) goto err; /* * Create the file on disk. We'll be putting the data * into the file via mpool. */ if ((ret = __os_open(dbenv, real_name, DB_OSO_CREATE, dbenv->db_mode, &rfh)) == 0) ret = __os_closehandle(dbenv, rfh); if (ret != 0) goto err; } if ((ret = __rep_mpf_open(dbenv, &rep->file_mpf, rep->curinfo)) != 0) goto err; } /* * Handle queue specially. If we're a QUEUE database, we need to * use the __qam_fget/put calls. We need to use rep->queue_dbp for * that. That dbp is opened after getting the metapage for the * queue database. Since the meta-page is always in the queue file, * we'll use the normal path for that first page. After that we * can assume the dbp is opened. */ if (msgfp->type == DB_QUEUE && msgfp->pgno != 0) {#ifdef HAVE_QUEUE if ((ret = __qam_fget( rep->queue_dbp, &msgfp->pgno, DB_MPOOL_CREATE, &dst)) != 0)#else if ((ret = __db_no_queue_am(dbenv)) != 0)#endif goto err; } else if ((ret = __memp_fget( rep->file_mpf, &msgfp->pgno, DB_MPOOL_CREATE, &dst)) != 0) goto err; memcpy(dst, msgfp->info.data, msgfp->pgsize); if (msgfp->type != DB_QUEUE || msgfp->pgno == 0) ret = __memp_fput(rep->file_mpf, dst, DB_MPOOL_DIRTY);#ifdef HAVE_QUEUE else ret = __qam_fput(rep->queue_dbp, msgfp->pgno, dst, DB_MPOOL_DIRTY);#endiferr: if (real_name != NULL) __os_free(dbenv, real_name); return (ret);}/* * __rep_page_gap - * After we've put the page into the database, we need to check if * we have a page gap and whether we need to request pages. */static int__rep_page_gap(dbenv, rep, msgfp, type) DB_ENV *dbenv; REP *rep; __rep_fileinfo_args *msgfp; u_int32_t type;{ DB_LOG *dblp; DB_REP *db_rep; DBT data, key; LOG *lp; __rep_fileinfo_args *rfp; db_recno_t recno; int ret;#ifdef DIAGNOSTIC DB_MSGBUF mb;#endif db_rep = dbenv->rep_handle; ret = 0; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; /* * We've successfully put this page into our file. * Now we need to account for it and re-request new pages * if necessary. */ /* * We already hold the rep mutex, but we also need the db mutex. * So we need to drop it, acquire both in the right order and * then recheck the state of the world. */ MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); MUTEX_LOCK(dbenv, db_rep->db_mutexp); MUTEX_LOCK(dbenv, db_rep->rep_mutexp); rfp = rep->curinfo; /* * Make sure we're still talking about the same file. * If not, we're done here. */ if (rfp->filenum != msgfp->filenum) { ret = DB_REP_PAGEDONE; goto err; } /* * We have 3 possible states: * 1. We receive a page we already have. * msg pgno < ready pgno * 2. We receive a page that is beyond a gap. * msg pgno > ready pgno * 3. We receive the page we're expecting. * msg pgno == ready pgno */ /* * State 1. This should not happen because this function * should only be called once per page received because we * check for DB_KEY_EXIST when we save the page information. */ DB_ASSERT(msgfp->pgno >= rep->ready_pg); /* * State 2. This page is beyond the page we're expecting. * We need to update waiting_pg if this page is less than * (earlier) the current waiting_pg. There is nothing * to do but see if we need to request. */ RPRINT(dbenv, rep, (dbenv, &mb, "PAGE_GAP: pgno %lu, max_pg %lu ready %lu, waiting %lu max_wait %lu", (u_long)msgfp->pgno, (u_long)rfp->max_pgno, (u_long)rep->ready_pg, (u_long)rep->waiting_pg, (u_long)rep->max_wait_pg)); if (msgfp->pgno > rep->ready_pg) { if (rep->waiting_pg == PGNO_INVALID || msgfp->pgno < rep->waiting_pg) rep->waiting_pg = msgfp->pgno; } else { /* * We received the page we're expecting. */ rep->ready_pg++; lp->rcvd_recs = 0; while (ret == 0 && rep->ready_pg == rep->waiting_pg) { /* * If we get here we know we just filled a gap. */ lp->wait_recs = 0; lp->rcvd_recs = 0; rep->max_wait_pg = PGNO_INVALID; /* * We need to walk the recno database looking for the * next page we need or expect. */ memset(&key, 0, sizeof(key)); memset(&data, 0, sizeof(data)); recno = (db_recno_t)rep->ready_pg; key.data = &recno; key.ulen = key.size = sizeof(db_recno_t); key.flags = DB_DBT_USERMEM; ret = __db_get(rep->file_dbp, NULL, &key, &data, 0); if (ret == DB_NOTFOUND || ret == DB_KEYEMPTY) break; else if (ret != 0) goto err; rep->ready_pg++; } } /* * If we filled a gap and now have the entire file, there's * nothing to do. We're done when ready_pg is > max_pgno * because ready_pg is larger than the last page we received. */ if (rep->ready_pg > rfp->max_pgno) goto err; /* * Check if we need to ask for more pages. */ if ((rep->waiting_pg != PGNO_INVALID && rep->ready_pg != rep->waiting_pg) || type == REP_PAGE_MORE) { /* * We got a page but we may still be waiting for more. */ if (lp->wait_recs == 0) { /* * This is a new gap. Initialize the number of * records that we should wait before requesting * that it be resent. We grab the limits out of * the rep without the mutex. */ lp->wait_recs = rep->request_gap; lp->rcvd_recs = 0; rep->max_wait_pg = PGNO_INVALID; } /* * If we got REP_PAGE_MORE we always want to ask for more. */ if ((__rep_check_doreq(dbenv, rep) || type == REP_PAGE_MORE) && ((ret = __rep_pggap_req(dbenv, rep, rfp, type == REP_PAGE_MORE)) != 0)) goto err; } else { lp->wait_recs = 0; rep->max_wait_pg = PGNO_INVALID; }err: MUTEX_UNLOCK(dbenv, db_rep->db_mutexp); return (ret);}/* * __rep_filedone - * We need to check if we're done with the current file after * processing the current page. Stat the database to see if * we have all the pages. If so, we need to clean up/close * this one, set up for the next one, and ask for its pages, * or if this is the last file, request the log records and * move to the REP_RECOVER_LOG state. */static int__rep_filedone(dbenv, eid, rep, msgfp, type) DB_ENV *dbenv; int eid; REP *rep; __rep_fileinfo_args *msgfp; u_int32_t type;{ DBT dbt; DB_REP *db_rep; __rep_fileinfo_args *rfp; int ret;#ifdef DIAGNOSTIC DB_MSGBUF mb;#endif db_rep = dbenv->rep_handle; /* * We've put our page, now we need to do any gap processing * that might be needed to re-request pages. */ ret = __rep_page_gap(dbenv, rep, msgfp, type); /* * The world changed while we were doing gap processing. * We're done here. */ if (ret == DB_REP_PAGEDONE) return (0); rfp = rep->curinfo; /* * max_pgno is 0-based and npages is 1-based, so we don't have * all the pages until npages is > max_pgno. */ RPRINT(dbenv, rep, (dbenv, &mb, "FILEDONE: have %lu pages. Need %lu.", (u_long)rep->npages, (u_long)rfp->max_pgno + 1)); if (rep->npages <= rfp->max_pgno) return (0); /* * If we're queue and we think we have all the pages for this file, * we need to do special queue processing. Queue is handled in * several stages. */ if (rfp->type == DB_QUEUE && ((ret = __rep_queue_filedone(dbenv, rep, rfp)) != DB_REP_PAGEDONE)) return (ret); /* * We have all the pages for this file. We need to: * 1. Close up the file data pointer we used. * 2. Close/reset the page database. * 3. Check if we have all file data. If so, request logs. * 4. If not, set curfile to next file and request its pages. */ /* * 1. Close up the file data pointer we used.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -