📄 rep_backup.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 2004 * Sleepycat Software. All rights reserved. * * $Id: rep_backup.c,v 1.33 2004/10/29 18:08:09 bostic Exp $ */#include "db_config.h"#ifndef NO_SYSTEM_INCLUDES#if TIME_WITH_SYS_TIME#include <sys/time.h>#include <time.h>#else#if HAVE_SYS_TIME_H#include <sys/time.h>#else#include <time.h>#endif#endif#include <string.h>#endif#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_shash.h"#include "dbinc/db_am.h"#include "dbinc/lock.h"#include "dbinc/log.h"#include "dbinc/mp.h"#include "dbinc/qam.h"#include "dbinc/txn.h"static int __rep_filedone __P((DB_ENV *, int, REP *, __rep_fileinfo_args *, u_int32_t));static int __rep_files_data __P((DB_ENV *, u_int8_t *, size_t *, size_t *, int *));static int __rep_files_inmem __P((DB_ENV *, u_int8_t *, size_t *, size_t *, int *));static int __rep_get_fileinfo __P((DB_ENV *, const char *, __rep_fileinfo_args *, u_int8_t *, int *));static int __rep_log_setup __P((DB_ENV *, REP *));static int __rep_mpf_open __P((DB_ENV *, DB_MPOOLFILE **, __rep_fileinfo_args *));static int __rep_page_gap __P((DB_ENV *, REP *, __rep_fileinfo_args *, u_int32_t));static int __rep_page_sendpages __P((DB_ENV *, int, __rep_fileinfo_args *, DB_MPOOLFILE *, DB *));static int __rep_queue_filedone __P((DB_ENV *, REP *, __rep_fileinfo_args *));static int __rep_walk_dir __P((DB_ENV *, const char *, u_int8_t *, size_t *, size_t *, int *));static int __rep_write_page __P((DB_ENV *, REP *, __rep_fileinfo_args *));/* * __rep_update_req - * Process an update_req and send the file information to the client. * * PUBLIC: int __rep_update_req __P((DB_ENV *, int)); */int__rep_update_req(dbenv, eid) DB_ENV *dbenv; int eid;{ DBT updbt; DB_LOG *dblp; DB_LOGC *logc; DB_LSN lsn; DBT data_dbt; size_t filelen, filesz, updlen; u_int8_t *buf, *fp; int filecnt, ret, t_ret; /* * Allocate enough for all currently open files and then some. * Optimize for the common use of having most databases open. * Allocate dbentry_cnt * 2 plus an estimated 60 bytes per * file for the filename/path (or multiplied by 120). * * The data we send looks like this: * __rep_update_args * __rep_fileinfo_args * __rep_fileinfo_args * ... */ dblp = dbenv->lg_handle; filecnt = 0; filelen = 0; updlen = 0; filesz = MEGABYTE; if ((ret = __os_calloc(dbenv, 1, filesz, &buf)) != 0) return (ret); /* * First get our file information. Get in-memory files first * then get on-disk files. */ fp = buf + sizeof(__rep_update_args); if ((ret = __rep_files_inmem(dbenv, fp, &filesz, &filelen, &filecnt)) != 0) goto err; if ((ret = __rep_files_data(dbenv, fp, &filesz, &filelen, &filecnt)) != 0) goto err; /* * Now get our first LSN. */ if ((ret = __log_cursor(dbenv, &logc)) != 0) goto err; memset(&data_dbt, 0, sizeof(data_dbt)); ret = __log_c_get(logc, &lsn, &data_dbt, DB_FIRST); if ((t_ret = __log_c_close(logc)) != 0 && ret == 0) ret = t_ret; if (ret != 0) goto err; /* * Package up the update information. */ if ((ret = __rep_update_buf(buf, filesz, &updlen, &lsn, filecnt)) != 0) goto err; /* * We have all the file information now. Send it to the client. */ memset(&updbt, 0, sizeof(updbt)); updbt.data = buf; updbt.size = (u_int32_t)(filelen + updlen); R_LOCK(dbenv, &dblp->reginfo); lsn = ((LOG *)dblp->reginfo.primary)->lsn; R_UNLOCK(dbenv, &dblp->reginfo); (void)__rep_send_message(dbenv, eid, REP_UPDATE, &lsn, &updbt, 0);err: __os_free(dbenv, buf); return (ret);}/* * __rep_files_data - * Walk through all the files in the env's data_dirs. We need to * open them, gather the necessary information and then close them. * Then we need to figure out if they're already in the dbentry array. */static int__rep_files_data(dbenv, fp, fileszp, filelenp, filecntp) DB_ENV *dbenv; u_int8_t *fp; size_t *fileszp, *filelenp; int *filecntp;{ int ret; char **ddir; ret = 0; if (dbenv->db_data_dir == NULL) { /* * If we don't have a data dir, we have just the * env home dir. */ ret = __rep_walk_dir(dbenv, dbenv->db_home, fp, fileszp, filelenp, filecntp); } else { for (ddir = dbenv->db_data_dir; *ddir != NULL; ++ddir) if ((ret = __rep_walk_dir(dbenv, *ddir, fp, fileszp, filelenp, filecntp)) != 0) break; } return (ret);}static int__rep_walk_dir(dbenv, dir, fp, fileszp, filelenp, filecntp) DB_ENV *dbenv; const char *dir; u_int8_t *fp; size_t *fileszp, *filelenp; int *filecntp;{ DBT namedbt, uiddbt; __rep_fileinfo_args tmpfp; size_t len, offset; int cnt, i, ret; u_int8_t *rfp, uid[DB_FILE_ID_LEN]; char **names;#ifdef DIAGNOSTIC REP *rep; DB_MSGBUF mb; DB_REP *db_rep; db_rep = dbenv->rep_handle; rep = db_rep->region;#endif memset(&namedbt, 0, sizeof(namedbt)); memset(&uiddbt, 0, sizeof(uiddbt)); RPRINT(dbenv, rep, (dbenv, &mb, "Walk_dir: Getting info for dir: %s", dir)); if ((ret = __os_dirlist(dbenv, dir, &names, &cnt)) != 0) return (ret); rfp = fp; RPRINT(dbenv, rep, (dbenv, &mb, "Walk_dir: Dir %s has %d files", dir, cnt)); for (i = 0; i < cnt; i++) { RPRINT(dbenv, rep, (dbenv, &mb, "Walk_dir: File %d name: %s", i, names[i])); /* * Skip DB-owned files: ., .., __db*, DB_CONFIG, log* */ if (strcmp(names[i], ".") == 0) continue; if (strcmp(names[i], "..") == 0) continue; if (strncmp(names[i], "__db", 4) == 0) continue; if (strncmp(names[i], "DB_CONFIG", 9) == 0) continue; if (strncmp(names[i], "log", 3) == 0) continue; /* * We found a file to process. Check if we need * to allocate more space. */ if ((ret = __rep_get_fileinfo(dbenv, names[i], &tmpfp, uid, filecntp)) != 0) { /* * If we find a file that isn't a database, skip it. */ RPRINT(dbenv, rep, (dbenv, &mb, "Walk_dir: File %d %s: returned error %s", i, names[i], db_strerror(ret))); ret = 0; continue; } RPRINT(dbenv, rep, (dbenv, &mb, "Walk_dir: File %d (of %d) %s: pgsize %lu, max_pgno %lu", tmpfp.filenum, i, names[i], (u_long)tmpfp.pgsize, (u_long)tmpfp.max_pgno)); namedbt.data = names[i]; namedbt.size = (u_int32_t)strlen(names[i]) + 1; uiddbt.data = uid; uiddbt.size = DB_FILE_ID_LEN;retry: ret = __rep_fileinfo_buf(rfp, *fileszp, &len, tmpfp.pgsize, tmpfp.pgno, tmpfp.max_pgno, tmpfp.filenum, tmpfp.id, tmpfp.type, tmpfp.flags, &uiddbt, &namedbt); if (ret == ENOMEM) { offset = (size_t)(rfp - fp); *fileszp *= 2; /* * Need to account for update info on both sides * of the allocation. */ fp -= sizeof(__rep_update_args); if ((ret = __os_realloc(dbenv, *fileszp, fp)) != 0) break; fp += sizeof(__rep_update_args); rfp = fp + offset; /* * Now that we've reallocated the space, try to * store it again. */ goto retry; } rfp += len; *filelenp += len; } __os_dirfree(dbenv, names, cnt); return (ret);}static int__rep_get_fileinfo(dbenv, file, rfp, uid, filecntp) DB_ENV *dbenv; const char *file; __rep_fileinfo_args *rfp; u_int8_t *uid; int *filecntp;{ DB *dbp, *entdbp; DB_LOCK lk; DB_LOG *dblp; DB_MPOOLFILE *mpf; DBC *dbc; DBMETA *dbmeta; PAGE *pagep; int i, ret, t_ret; dbp = NULL; dbc = NULL; pagep = NULL; mpf = NULL; LOCK_INIT(lk); dblp = dbenv->lg_handle; if ((ret = db_create(&dbp, dbenv, 0)) != 0) goto err; if ((ret = __db_open(dbp, NULL, file, NULL, DB_UNKNOWN, DB_RDONLY | (F_ISSET(dbenv, DB_ENV_THREAD) ? DB_THREAD : 0), 0, PGNO_BASE_MD)) != 0) goto err; if ((ret = __db_cursor(dbp, NULL, &dbc, 0)) != 0) goto err; if ((ret = __db_lget( dbc, 0, dbp->meta_pgno, DB_LOCK_READ, 0, &lk)) != 0) goto err; if ((ret = __memp_fget(dbp->mpf, &dbp->meta_pgno, 0, &pagep)) != 0) goto err; /* * We have the meta page. Set up our information. */ dbmeta = (DBMETA *)pagep; rfp->pgno = 0; /* * Queue is a special-case. We need to set max_pgno to 0 so that * the client can compute the pages from the meta-data. */ if (dbp->type == DB_QUEUE) rfp->max_pgno = 0; else rfp->max_pgno = dbmeta->last_pgno; rfp->pgsize = dbp->pgsize; memcpy(uid, dbp->fileid, DB_FILE_ID_LEN); rfp->filenum = (*filecntp)++; rfp->type = dbp->type; rfp->flags = dbp->flags; rfp->id = DB_LOGFILEID_INVALID; ret = __memp_fput(dbp->mpf, pagep, 0); pagep = NULL; if ((t_ret = __LPUT(dbc, lk)) != 0 && ret == 0) ret = t_ret; if (ret != 0) goto err;err: if ((t_ret = __LPUT(dbc, lk)) != 0 && ret == 0) ret = t_ret; if (dbc != NULL && (t_ret = __db_c_close(dbc)) != 0 && ret == 0) ret = t_ret; if (pagep != NULL && (t_ret = __memp_fput(mpf, pagep, 0)) != 0 && ret == 0) ret = t_ret; if (dbp != NULL && (t_ret = __db_close(dbp, NULL, 0)) != 0 && ret == 0) ret = t_ret; /* * We walk the entry table now, after closing the dbp because * otherwise we find the open from this function and the id * is useless in that case. */ if (ret == 0) { MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); /* * Walk entry table looking for this uid. * If we find it, save the id. */ for (i = 0; i < dblp->dbentry_cnt; i++) { entdbp = dblp->dbentry[i].dbp; if (entdbp == NULL) break; DB_ASSERT(entdbp->log_filename != NULL); if (memcmp(uid, entdbp->log_filename->ufid, DB_FILE_ID_LEN) == 0) rfp->id = i; } MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); } return (ret);}/* * __rep_files_inmem - * Gather all the information about in-memory files. */static int__rep_files_inmem(dbenv, fp, fileszp, filelenp, filecntp) DB_ENV *dbenv; u_int8_t *fp; size_t *fileszp, *filelenp; int *filecntp;{ int ret; COMPQUIET(dbenv, NULL); COMPQUIET(fp, NULL); COMPQUIET(fileszp, NULL); COMPQUIET(filelenp, NULL); COMPQUIET(filecntp, NULL); ret = 0; return (ret);}/* * __rep_page_req * Process a page_req and send the page information to the client. * * PUBLIC: int __rep_page_req __P((DB_ENV *, int, DBT *)); */int__rep_page_req(dbenv, eid, rec) DB_ENV *dbenv; int eid; DBT *rec;{ DB *dbp; DBT msgdbt; DB_LOG *dblp; DB_MPOOLFILE *mpf; __rep_fileinfo_args *msgfp; int ret, t_ret; void *next;#ifdef DIAGNOSTIC DB_MSGBUF mb; DB_REP *db_rep; REP *rep; db_rep = dbenv->rep_handle; rep = db_rep->region;#endif dblp = dbenv->lg_handle; if ((ret = __rep_fileinfo_read(dbenv, rec->data, &next, &msgfp)) != 0) return (ret); /* * See if we can find it already. If so we can quickly * access its mpool and process. Otherwise we have to * open the file ourselves. */ RPRINT(dbenv, rep, (dbenv, &mb, "page_req: file %d page %lu to %lu", msgfp->filenum, (u_long)msgfp->pgno, (u_long)msgfp->max_pgno)); MUTEX_THREAD_LOCK(dbenv, dblp->mutexp); if (msgfp->id >= 0 && dblp->dbentry_cnt > msgfp->id) { dbp = dblp->dbentry[msgfp->id].dbp; if (dbp != NULL) { DB_ASSERT(dbp->log_filename != NULL); if (memcmp(msgfp->uid.data, dbp->log_filename->ufid, DB_FILE_ID_LEN) == 0) { MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp); RPRINT(dbenv, rep, (dbenv, &mb, "page_req: found %d in dbreg", msgfp->filenum)); ret = __rep_page_sendpages(dbenv, eid, msgfp, dbp->mpf, dbp); goto err; } } } MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -