📄 rep_record.c
字号:
ret = __rep_send_file(dbenv, rec, *eidp); goto errlock;#endif case REP_FILE_FAIL: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); /* * XXX */ break; case REP_LOG: case REP_LOG_MORE: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); is_dup = 0; ret = __rep_apply(dbenv, rp, rec, ret_lsnp, &is_dup); switch (ret) { /* * We're in an internal backup and we've gotten * all the log we need to run recovery. Do so now. */ case DB_REP_LOGREADY: if ((ret = __log_flush(dbenv, NULL)) != 0) goto errlock; if ((ret = __rep_verify_match(dbenv, &rep->last_lsn, savetime)) == 0) { MUTEX_LOCK(dbenv, db_rep->rep_mutexp); ZERO_LSN(rep->first_lsn); ZERO_LSN(rep->last_lsn); F_CLR(rep, REP_F_RECOVER_LOG); MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); } break; /* * If we get any of the "normal" returns, we only process * LOG_MORE if this is not a duplicate record. If the * record is a duplicate we don't want to handle LOG_MORE * and request a multiple data stream (or trigger internal * initialization) since this could be a very old record * that no longer exists on the master. */ case DB_REP_ISPERM: case DB_REP_NOTPERM: case 0: if (is_dup) goto errlock; else break; /* * Any other return (errors), we're done. */ default: goto errlock; } if (rp->rectype == REP_LOG_MORE) { MUTEX_LOCK(dbenv, db_rep->rep_mutexp); master = rep->master_id; MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); R_LOCK(dbenv, &dblp->reginfo); lsn = lp->lsn; R_UNLOCK(dbenv, &dblp->reginfo); /* * If the master_id is invalid, this means that since * the last record was sent, somebody declared an * election and we may not have a master to request * things of. * * This is not an error; when we find a new master, * we'll re-negotiate where the end of the log is and * try to bring ourselves up to date again anyway. */ MUTEX_LOCK(dbenv, db_rep->db_mutexp); if (master == DB_EID_INVALID) ret = 0; /* * If we've asked for a bunch of records, it could * either be from a LOG_REQ or ALL_REQ. If we're * waiting for a gap to be filled, call loggap_req, * otherwise use ALL_REQ again. */ else if (IS_ZERO_LSN(lp->waiting_lsn)) { MUTEX_UNLOCK(dbenv, db_rep->db_mutexp); if (__rep_send_message(dbenv, master, REP_ALL_REQ, &lsn, NULL, 0) != 0) break; } else { __rep_loggap_req(dbenv, rep, &lsn, 1); MUTEX_UNLOCK(dbenv, db_rep->db_mutexp); } } goto errlock; case REP_LOG_REQ: MASTER_ONLY(rep, rp); if (rec != NULL && rec->size != 0) { RPRINT(dbenv, rep, (dbenv, &mb, "[%lu][%lu]: LOG_REQ max lsn: [%lu][%lu]", (u_long) rp->lsn.file, (u_long)rp->lsn.offset, (u_long)((DB_LSN *)rec->data)->file, (u_long)((DB_LSN *)rec->data)->offset)); } /* * There are three different cases here. * 1. We asked for a particular LSN and got it. * 2. We asked for an LSN and it's not found because it is * beyond the end of a log file and we need a NEWFILE msg. * and then the record that was requested. * 3. We asked for an LSN and it simply doesn't exist, but * doesn't meet any of those other criteria, in which case * it's an error (that should never happen). * If we have a valid LSN and the request has a data_dbt with * it, then we need to send all records up to the LSN in the * data dbt. */ oldfilelsn = lsn = rp->lsn; if ((ret = __log_cursor(dbenv, &logc)) != 0) goto errlock; memset(&data_dbt, 0, sizeof(data_dbt)); ret = __log_c_get(logc, &lsn, &data_dbt, DB_SET); if (ret == 0) /* Case 1 */ (void)__rep_send_message(dbenv, *eidp, REP_LOG, &lsn, &data_dbt, DB_LOG_RESEND); else if (ret == DB_NOTFOUND) { R_LOCK(dbenv, &dblp->reginfo); endlsn = lp->lsn; R_UNLOCK(dbenv, &dblp->reginfo); if (endlsn.file > lsn.file) { /* * Case 2: * Need to find the LSN of the last record in * file lsn.file so that we can send it with * the NEWFILE call. In order to do that, we * need to try to get {lsn.file + 1, 0} and * then backup. */ endlsn.file = lsn.file + 1; endlsn.offset = 0; if ((ret = __log_c_get(logc, &endlsn, &data_dbt, DB_SET)) != 0 || (ret = __log_c_get(logc, &endlsn, &data_dbt, DB_PREV)) != 0) { RPRINT(dbenv, rep, (dbenv, &mb, "Unable to get prev of [%lu][%lu]", (u_long)lsn.file, (u_long)lsn.offset)); /* * We want to push the error back * to the client so that the client * does an internal backup. The * client asked for a log record * we no longer have and it is * outdated. * XXX - This could be optimized by * having the master perform and * send a REP_UPDATE message. We * currently want the client to set * up its 'update' state prior to * requesting REP_UPDATE_REQ. */ ret = 0; (void)__rep_send_message(dbenv, *eidp, REP_VERIFY_FAIL, &rp->lsn, NULL, 0); } else { endlsn.offset += logc->c_len; (void)__rep_send_message(dbenv, *eidp, REP_NEWFILE, &endlsn, NULL, 0); } } else { /* Case 3 */ __db_err(dbenv, "Request for LSN [%lu][%lu] fails", (u_long)lsn.file, (u_long)lsn.offset); DB_ASSERT(0); ret = EINVAL; } } /* * If the user requested a gap, send the whole thing, * while observing the limits from set_rep_limit. */ MUTEX_LOCK(dbenv, db_rep->rep_mutexp); gbytes = rep->gbytes; bytes = rep->bytes; MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); check_limit = gbytes != 0 || bytes != 0; type = REP_LOG; while (ret == 0 && rec != NULL && rec->size != 0 && type == REP_LOG) { if ((ret = __log_c_get(logc, &lsn, &data_dbt, DB_NEXT)) != 0) { if (ret == DB_NOTFOUND) ret = 0; break; } if (log_compare(&lsn, (DB_LSN *)rec->data) >= 0) break; /* * When a log file changes, we'll have a real log * record with some lsn [n][m], and we'll also want * to send a NEWFILE message with lsn [n-1][MAX]. */ if (lsn.file != oldfilelsn.file) (void)__rep_send_message(dbenv, *eidp, REP_NEWFILE, &oldfilelsn, NULL, 0); if (check_limit) { /* * data_dbt.size is only the size of the log * record; it doesn't count the size of the * control structure. Factor that in as well * so we're not off by a lot if our log records * are small. */ while (bytes < data_dbt.size + sizeof(REP_CONTROL)) { if (gbytes > 0) { bytes += GIGABYTE; --gbytes; continue; } /* * We don't hold the rep mutex, * and may miscount. */ rep->stat.st_nthrottles++; type = REP_LOG_MORE; goto send1; } bytes -= (data_dbt.size + sizeof(REP_CONTROL)); }send1: if (__rep_send_message(dbenv, *eidp, type, &lsn, &data_dbt, DB_LOG_RESEND) != 0) break; /* * If we are about to change files, then we'll need the * last LSN in the previous file. Save it here. */ oldfilelsn = lsn; oldfilelsn.offset += logc->c_len; } if ((t_ret = __log_c_close(logc)) != 0 && ret == 0) ret = t_ret; goto errlock; case REP_NEWSITE: /* We don't hold the rep mutex, and may miscount. */ rep->stat.st_newsites++; /* This is a rebroadcast; simply tell the application. */ if (F_ISSET(rep, REP_F_MASTER)) { dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; R_LOCK(dbenv, &dblp->reginfo); lsn = lp->lsn; R_UNLOCK(dbenv, &dblp->reginfo); (void)__rep_send_message(dbenv, *eidp, REP_NEWMASTER, &lsn, NULL, 0); } ret = DB_REP_NEWSITE; goto errlock; case REP_NEWCLIENT: /* * This message was received and should have resulted in the * application entering the machine ID in its machine table. * We respond to this with an ALIVE to send relevant information * to the new client (if we are a master, we'll send a * NEWMASTER, so we only need to send the ALIVE if we're a * client). But first, broadcast the new client's record to * all the clients. */ (void)__rep_send_message(dbenv, DB_EID_BROADCAST, REP_NEWSITE, &rp->lsn, rec, 0); ret = DB_REP_NEWSITE; if (F_ISSET(rep, REP_F_CLIENT)) { MUTEX_LOCK(dbenv, db_rep->rep_mutexp); egen = rep->egen; if (*eidp == rep->master_id) rep->master_id = DB_EID_INVALID; MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); data_dbt.data = &egen; data_dbt.size = sizeof(egen); (void)__rep_send_message(dbenv, DB_EID_BROADCAST, REP_ALIVE, &rp->lsn, &data_dbt, 0); goto errlock; } /* FALLTHROUGH */ case REP_MASTER_REQ: if (F_ISSET(rep, REP_F_MASTER)) { R_LOCK(dbenv, &dblp->reginfo); lsn = lp->lsn; R_UNLOCK(dbenv, &dblp->reginfo); (void)__rep_send_message(dbenv, DB_EID_BROADCAST, REP_NEWMASTER, &lsn, NULL, 0); } /* * If there is no master, then we could get into a state * where an old client lost the initial ALIVE message and * is calling an election under an old gen and can * never get to the current gen. */ if (F_ISSET(rep, REP_F_CLIENT) && rp->gen < gen) { MUTEX_LOCK(dbenv, db_rep->rep_mutexp); egen = rep->egen; if (*eidp == rep->master_id) rep->master_id = DB_EID_INVALID; MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); data_dbt.data = &egen; data_dbt.size = sizeof(egen); (void)__rep_send_message(dbenv, *eidp, REP_ALIVE, &rp->lsn, &data_dbt, 0); goto errlock; } goto errlock; case REP_NEWFILE: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); ret = __rep_apply(dbenv, rp, rec, ret_lsnp, NULL); goto errlock; case REP_NEWMASTER: ANYSITE(rep); if (F_ISSET(rep, REP_F_MASTER) && *eidp != dbenv->rep_eid) { /* We don't hold the rep mutex, and may miscount. */ rep->stat.st_dupmasters++; ret = DB_REP_DUPMASTER; (void)__rep_send_message(dbenv, DB_EID_BROADCAST, REP_DUPMASTER, NULL, NULL, 0); goto errlock; } ret = __rep_new_master(dbenv, rp, *eidp); goto errlock; case REP_PAGE: case REP_PAGE_MORE: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); ret = __rep_page(dbenv, *eidp, rp, rec); break; case REP_PAGE_FAIL: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); ret = __rep_page_fail(dbenv, *eidp, rec); break; case REP_PAGE_REQ: MASTER_ONLY(rep, rp); MASTER_UPDATE(dbenv, renv); ret = __rep_page_req(dbenv, *eidp, rec); break; case REP_UPDATE: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); ret = __rep_update_setup(dbenv, *eidp, rp, rec); break; case REP_UPDATE_REQ: MASTER_ONLY(rep, rp); infop = dbenv->reginfo; renv = infop->primary; MASTER_UPDATE(dbenv, renv); ret = __rep_update_req(dbenv, *eidp); break; case REP_VERIFY: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); if (IS_ZERO_LSN(lp->verify_lsn)) goto errlock; if ((ret = __log_cursor(dbenv, &logc)) != 0) goto errlock; memset(&mylog, 0, sizeof(mylog)); if ((ret = __log_c_get(logc, &rp->lsn, &mylog, DB_SET)) != 0) goto rep_verify_err; match = 0; memcpy(&rectype, mylog.data, sizeof(rectype)); if (mylog.size == rec->size && memcmp(mylog.data, rec->data, rec->size) == 0) match = 1; DB_ASSERT(rectype == DB___txn_ckp); /* * If we don't have a match, backup to the previous * checkpoint and try again. */ if (match == 0) { ZERO_LSN(lsn); if ((ret = __log_backup(dbenv, logc, &rp->lsn, &lsn, LASTCKP_CMP)) == 0) { MUTEX_LOCK(dbenv, db_rep->db_mutexp); lp->verify_lsn = lsn; lp->rcvd_recs = 0; lp->wait_recs = rep->request_gap; MUTEX_UNLOCK(dbenv, db_rep->db_mutexp); (void)__rep_send_message(dbenv, *eidp, REP_VERIFY_REQ, &lsn, NULL, 0); } else if (ret == DB_NOTFOUND) { /* * We've either run out of records because * logs have been removed or we've rolled back * all the way to the beginning. In the latter * we don't think these sites were ever part of * the same environment and we'll say so. * In the former, request internal backup. */ if (rp->lsn.file == 1) { __db_err(dbenv, "Client was never part of master's environment"); ret = EINVAL; } else { rep->stat.st_outdated++; R_LOCK(dbenv, &dblp->reginfo); lsn = lp->lsn; R_UNLOCK(dbenv, &dblp->reginfo); MUTEX_LOCK(dbenv, db_rep->rep_mutexp); F_CLR(rep, REP_F_RECOVER_VERIFY); F_SET(rep, REP_F_RECOVER_UPDATE); ZERO_LSN(rep->first_lsn); MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); (void)__rep_send_message(dbenv, *eidp, REP_UPDATE_REQ, NULL, NULL, 0); } } } else ret = __rep_verify_match(dbenv, &rp->lsn, savetime);rep_verify_err: if ((t_ret = __log_c_close(logc)) != 0 && ret == 0) ret = t_ret; goto errlock; case REP_VERIFY_FAIL: CLIENT_ONLY(rep, rp); MASTER_CHECK(dbenv, *eidp, rep); /* * If any recovery flags are set, but not VERIFY, * then we ignore this message. We are already * in the middle of updating. */ if (F_ISSET(rep, REP_F_RECOVER_MASK) && !F_ISSET(rep, REP_F_RECOVER_VERIFY)) goto errlock; rep->stat.st_outdated++; MUTEX_LOCK(dbenv, db_rep->db_mutexp); MUTEX_LOCK(dbenv, db_rep->rep_mutexp); /* * We don't want an old or delayed VERIFY_FAIL * message to throw us into internal initialization * when we shouldn't be. * * Only go into internal initialization if: * We are in RECOVER_VERIFY and this LSN == verify_lsn. * We are not in any RECOVERY and we are expecting * an LSN that no longer exists on the master. * Otherwise, ignore this message. */ if (((F_ISSET(rep, REP_F_RECOVER_VERIFY)) && log_compare(&rp->lsn, &lp->verify_lsn) == 0) || (F_ISSET(rep, REP_F_RECOVER_MASK) == 0 && log_compare(&rp->lsn, &lp->ready_lsn) >= 0)) { F_CLR(rep, REP_F_RECOVER_VERIFY); F_SET(rep, REP_F_RECOVER_UPDATE); ZERO_LSN(rep->first_lsn); lp->wait_recs = rep->request_gap; MUTEX_UNLOCK(dbenv, db_rep->rep_mutexp); MUTEX_UNLOCK(dbenv, db_rep->db_mutexp); (void)__rep_send_message(dbenv, *eidp, REP_UPDATE_REQ, NULL, NULL, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -