📄 log_put.c
字号:
if (release) R_LOCK(dbenv, &dblp->reginfo); lp->in_flush--; ++lp->stat.st_scount; /* * How many flush calls (usually commits) did this call actually sync? * At least one, if it got here. */ ncommit = 1;done: if (lp->ncommit != 0) { first = 1; for (commit = SH_TAILQ_FIRST(&lp->commits, __db_commit); commit != NULL; commit = SH_TAILQ_NEXT(commit, links, __db_commit)) if (log_compare(&lp->s_lsn, &commit->lsn) > 0) { MUTEX_UNLOCK(dbenv, &commit->mutex); SH_TAILQ_REMOVE( &lp->commits, commit, links, __db_commit); ncommit++; } else if (first == 1) { F_SET(commit, DB_COMMIT_FLUSH); MUTEX_UNLOCK(dbenv, &commit->mutex); SH_TAILQ_REMOVE( &lp->commits, commit, links, __db_commit); /* * This thread will wake and flush. * If another thread commits and flushes * first we will waste a trip trough the * mutex. */ lp->in_flush++; first = 0; } } if (lp->stat.st_maxcommitperflush < ncommit) lp->stat.st_maxcommitperflush = ncommit; if (lp->stat.st_mincommitperflush > ncommit || lp->stat.st_mincommitperflush == 0) lp->stat.st_mincommitperflush = ncommit; return (ret);}/* * __log_fill -- * Write information into the log. */static int__log_fill(dblp, lsn, addr, len) DB_LOG *dblp; DB_LSN *lsn; void *addr; u_int32_t len;{ LOG *lp; u_int32_t bsize, nrec; size_t nw, remain; int ret; lp = dblp->reginfo.primary; bsize = lp->buffer_size; if (lp->db_log_inmemory) { __log_inmem_copyin(dblp, lp->b_off, addr, len); lp->b_off = (lp->b_off + len) % lp->buffer_size; return (0); } while (len > 0) { /* Copy out the data. */ /* * If we're beginning a new buffer, note the user LSN to which * the first byte of the buffer belongs. We have to know this * when flushing the buffer so that we know if the in-memory * buffer needs to be flushed. */ if (lp->b_off == 0) lp->f_lsn = *lsn; /* * If we're on a buffer boundary and the data is big enough, * copy as many records as we can directly from the data. */ if (lp->b_off == 0 && len >= bsize) { nrec = len / bsize; if ((ret = __log_write(dblp, addr, nrec * bsize)) != 0) return (ret); addr = (u_int8_t *)addr + nrec * bsize; len -= nrec * bsize; ++lp->stat.st_wcount_fill; continue; } /* Figure out how many bytes we can copy this time. */ remain = bsize - lp->b_off; nw = remain > len ? len : remain; memcpy(dblp->bufp + lp->b_off, addr, nw); addr = (u_int8_t *)addr + nw; len -= (u_int32_t)nw; lp->b_off += nw; /* If we fill the buffer, flush it. */ if (lp->b_off == bsize) { if ((ret = __log_write(dblp, dblp->bufp, bsize)) != 0) return (ret); lp->b_off = 0; ++lp->stat.st_wcount_fill; } } return (0);}/* * __log_write -- * Write the log buffer to disk. */static int__log_write(dblp, addr, len) DB_LOG *dblp; void *addr; u_int32_t len;{ DB_ENV *dbenv; LOG *lp; size_t nw; int ret; dbenv = dblp->dbenv; lp = dblp->reginfo.primary; DB_ASSERT(!lp->db_log_inmemory); /* * If we haven't opened the log file yet or the current one has * changed, acquire a new log file. We are creating the file if we're * about to write to the start of it, in other words, if the write * offset is zero. */ if (dblp->lfhp == NULL || dblp->lfname != lp->lsn.file) if ((ret = __log_newfh(dblp, lp->w_off == 0)) != 0) return (ret); /* * If we're writing the first block in a log file on a filesystem that * guarantees unwritten blocks are zero-filled, we set the size of the * file in advance. This increases sync performance on some systems, * because they don't need to update metadata on every sync. */#ifdef HAVE_FILESYSTEM_NOTZERO if (lp->w_off == 0 && !__os_fs_notzero())#else if (lp->w_off == 0)#endif ret = __db_fileinit(dbenv, dblp->lfhp, lp->log_size, 0); /* * Seek to the offset in the file (someone may have written it * since we last did). */ if ((ret = __os_seek(dbenv, dblp->lfhp, 0, 0, lp->w_off, 0, DB_OS_SEEK_SET)) != 0 || (ret = __os_write(dbenv, dblp->lfhp, addr, len, &nw)) != 0) return (ret); /* Reset the buffer offset and update the seek offset. */ lp->w_off += len; /* Update written statistics. */ if ((lp->stat.st_w_bytes += len) >= MEGABYTE) { lp->stat.st_w_bytes -= MEGABYTE; ++lp->stat.st_w_mbytes; } if ((lp->stat.st_wc_bytes += len) >= MEGABYTE) { lp->stat.st_wc_bytes -= MEGABYTE; ++lp->stat.st_wc_mbytes; } ++lp->stat.st_wcount; return (0);}/* * __log_file_pp -- * DB_ENV->log_file pre/post processing. * * PUBLIC: int __log_file_pp __P((DB_ENV *, const DB_LSN *, char *, size_t)); */int__log_file_pp(dbenv, lsn, namep, len) DB_ENV *dbenv; const DB_LSN *lsn; char *namep; size_t len;{ int rep_check, ret; PANIC_CHECK(dbenv); ENV_REQUIRES_CONFIG(dbenv, dbenv->lg_handle, "DB_ENV->log_file", DB_INIT_LOG); if (F_ISSET(dbenv, DB_ENV_LOG_INMEMORY)) { __db_err(dbenv, "DB_ENV->log_file is illegal with in-memory logs."); return (EINVAL); } rep_check = IS_ENV_REPLICATED(dbenv) ? 1 : 0; if (rep_check) __env_rep_enter(dbenv); ret = __log_file(dbenv, lsn, namep, len); if (rep_check) __env_db_rep_exit(dbenv); return (ret);}/* * __log_file -- * DB_ENV->log_file. */static int__log_file(dbenv, lsn, namep, len) DB_ENV *dbenv; const DB_LSN *lsn; char *namep; size_t len;{ DB_LOG *dblp; int ret; char *name; dblp = dbenv->lg_handle; R_LOCK(dbenv, &dblp->reginfo); ret = __log_name(dblp, lsn->file, &name, NULL, 0); R_UNLOCK(dbenv, &dblp->reginfo); if (ret != 0) return (ret); /* Check to make sure there's enough room and copy the name. */ if (len < strlen(name) + 1) { *namep = '\0'; __db_err(dbenv, "DB_ENV->log_file: name buffer is too short"); return (EINVAL); } (void)strcpy(namep, name); __os_free(dbenv, name); return (0);}/* * __log_newfh -- * Acquire a file handle for the current log file. */static int__log_newfh(dblp, create) DB_LOG *dblp; int create;{ DB_ENV *dbenv; LOG *lp; u_int32_t flags; int ret; logfile_validity status; dbenv = dblp->dbenv; lp = dblp->reginfo.primary; /* Close any previous file descriptor. */ if (dblp->lfhp != NULL) { (void)__os_closehandle(dbenv, dblp->lfhp); dblp->lfhp = NULL; } flags = DB_OSO_LOG | DB_OSO_SEQ | (create ? DB_OSO_CREATE : 0) | (F_ISSET(dbenv, DB_ENV_DIRECT_LOG) ? DB_OSO_DIRECT : 0) | (F_ISSET(dbenv, DB_ENV_DSYNC_LOG) ? DB_OSO_DSYNC : 0); /* Get the path of the new file and open it. */ dblp->lfname = lp->lsn.file; if ((ret = __log_valid(dblp, dblp->lfname, 0, &dblp->lfhp, flags, &status)) != 0) __db_err(dbenv, "DB_ENV->log_put: %d: %s", lp->lsn.file, db_strerror(ret)); else if (status != DB_LV_NORMAL && status != DB_LV_INCOMPLETE) ret = DB_NOTFOUND; return (ret);}/* * __log_name -- * Return the log name for a particular file, and optionally open it. * * PUBLIC: int __log_name __P((DB_LOG *, * PUBLIC: u_int32_t, char **, DB_FH **, u_int32_t)); */int__log_name(dblp, filenumber, namep, fhpp, flags) DB_LOG *dblp; u_int32_t filenumber, flags; char **namep; DB_FH **fhpp;{ DB_ENV *dbenv; LOG *lp; int ret; char *oname; char old[sizeof(LFPREFIX) + 5 + 20], new[sizeof(LFPREFIX) + 10 + 20]; dbenv = dblp->dbenv; lp = dblp->reginfo.primary; DB_ASSERT(!lp->db_log_inmemory); /* * !!! * The semantics of this routine are bizarre. * * The reason for all of this is that we need a place where we can * intercept requests for log files, and, if appropriate, check for * both the old-style and new-style log file names. The trick is * that all callers of this routine that are opening the log file * read-only want to use an old-style file name if they can't find * a match using a new-style name. The only down-side is that some * callers may check for the old-style when they really don't need * to, but that shouldn't mess up anything, and we only check for * the old-style name when we've already failed to find a new-style * one. * * Create a new-style file name, and if we're not going to open the * file, return regardless. */ (void)snprintf(new, sizeof(new), LFNAME, filenumber); if ((ret = __db_appname(dbenv, DB_APP_LOG, new, 0, NULL, namep)) != 0 || fhpp == NULL) return (ret); /* Open the new-style file -- if we succeed, we're done. */ if ((ret = __os_open_extend(dbenv, *namep, 0, flags, (int)lp->persist.mode, fhpp)) == 0) return (0); /* * The open failed... if the DB_RDONLY flag isn't set, we're done, * the caller isn't interested in old-style files. */ if (!LF_ISSET(DB_OSO_RDONLY)) { __db_err(dbenv, "%s: log file open failed: %s", *namep, db_strerror(ret)); return (__db_panic(dbenv, ret)); } /* Create an old-style file name. */ (void)snprintf(old, sizeof(old), LFNAME_V1, filenumber); if ((ret = __db_appname(dbenv, DB_APP_LOG, old, 0, NULL, &oname)) != 0) goto err; /* * Open the old-style file -- if we succeed, we're done. Free the * space allocated for the new-style name and return the old-style * name to the caller. */ if ((ret = __os_open(dbenv, oname, flags, (int)lp->persist.mode, fhpp)) == 0) { __os_free(dbenv, *namep); *namep = oname; return (0); } /* * Couldn't find either style of name -- return the new-style name * for the caller's error message. If it's an old-style name that's * actually missing we're going to confuse the user with the error * message, but that implies that not only were we looking for an * old-style name, but we expected it to exist and we weren't just * looking for any log file. That's not a likely error. */err: __os_free(dbenv, oname); return (ret);}/* * __log_rep_put -- * Short-circuit way for replication clients to put records into the * log. Replication clients' logs need to be laid out exactly their masters' * are, so we let replication take responsibility for when the log gets * flushed, when log switches files, etc. This is just a thin PUBLIC wrapper * for __log_putr with a slightly prettier interface. * * Note that the db_rep->db_mutexp should be held when this is called. * Note that we acquire the log region lock while holding db_mutexp. * * PUBLIC: int __log_rep_put __P((DB_ENV *, DB_LSN *, const DBT *)); */int__log_rep_put(dbenv, lsnp, rec) DB_ENV *dbenv; DB_LSN *lsnp; const DBT *rec;{ DB_CIPHER *db_cipher; DB_LOG *dblp; HDR hdr; DBT *dbt, t; LOG *lp; int need_free, ret; dblp = dbenv->lg_handle; lp = dblp->reginfo.primary; R_LOCK(dbenv, &dblp->reginfo); memset(&hdr, 0, sizeof(HDR)); t = *rec; dbt = &t; need_free = 0; db_cipher = (DB_CIPHER *)dbenv->crypto_handle; if (CRYPTO_ON(dbenv)) t.size += db_cipher->adj_size(rec->size); if ((ret = __os_calloc(dbenv, 1, t.size, &t.data)) != 0) goto err; need_free = 1; memcpy(t.data, rec->data, rec->size); if ((ret = __log_encrypt_record(dbenv, dbt, &hdr, rec->size)) != 0) goto err; __db_chksum(t.data, t.size, (CRYPTO_ON(dbenv)) ? db_cipher->mac_key : NULL, hdr.chksum); DB_ASSERT(log_compare(lsnp, &lp->lsn) == 0); ret = __log_putr(dblp, lsnp, dbt, lp->lsn.offset - lp->len, &hdr);err: /* * !!! Assume caller holds db_rep->db_mutex to modify ready_lsn. */ lp->ready_lsn = lp->lsn; R_UNLOCK(dbenv, &dblp->reginfo); if (need_free) __os_free(dbenv, t.data); return (ret);}static int__log_encrypt_record(dbenv, dbt, hdr, orig) DB_ENV *dbenv; DBT *dbt; HDR *hdr; u_int32_t orig;{ DB_CIPHER *db_cipher; int ret; if (CRYPTO_ON(dbenv)) { db_cipher = (DB_CIPHER *)dbenv->crypto_handle; hdr->size = HDR_CRYPTO_SZ; hdr->orig_size = orig; if ((ret = db_cipher->encrypt(dbenv, db_cipher->data, hdr->iv, dbt->data, dbt->size)) != 0) return (ret); } else { hdr->size = HDR_NORMAL_SZ; } return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -