📄 log_get.c
字号:
for (p = dblp->bufp + (lp->b_off - lp->len);;) { memcpy(hdr, p, hdr->size); if (hdr->prev == lsn->offset) { b_region = (u_int32_t)(p - dblp->bufp); break; } p = dblp->bufp + (hdr->prev - lp->w_off); } /* * If we don't have enough room for the record, we have to allocate * space. We have to do it while holding the region lock, which is * truly annoying, but there's no way around it. This call is why * we allocate cursor buffer space when allocating the cursor instead * of waiting. */ if (logc->bp_size <= b_region + b_disk) { len = (size_t)DB_ALIGN((b_region + b_disk) * 2, 128); if ((ret = __os_realloc(logc->dbenv, len, &logc->bp)) != 0) return (ret); logc->bp_size = (u_int32_t)len; } /* Copy the region's bytes to the end of the cursor's buffer. */ p = (logc->bp + logc->bp_size) - b_region; memcpy(p, dblp->bufp, b_region); /* Release the region lock. */ if (*rlockp == L_ACQUIRED) { *rlockp = L_NONE; R_UNLOCK(dbenv, &dblp->reginfo); } /* * Read the rest of the information from disk. Neither short reads * or EOF are acceptable, the bytes we want had better be there. */ if (b_disk != 0) { p -= b_disk; nr = b_disk; if ((ret = __log_c_io( logc, lsn->file, lsn->offset, p, &nr, NULL)) != 0) return (ret); if (nr < b_disk) return (__log_c_shortread(logc, lsn, 0)); } /* Copy the header information into the caller's structure. */ memcpy(hdr, p, hdr->size); *pp = p; return (0);}/* * __log_c_ondisk -- * Read a record off disk. */static int__log_c_ondisk(logc, lsn, last_lsn, flags, hdr, pp, eofp) DB_LOGC *logc; DB_LSN *lsn, *last_lsn; u_int32_t flags; int *eofp; HDR *hdr; u_int8_t **pp;{ DB_ENV *dbenv; size_t len, nr; u_int32_t offset; int ret; dbenv = logc->dbenv; *eofp = 0; nr = hdr->size; if ((ret = __log_c_io(logc, lsn->file, lsn->offset, hdr, &nr, eofp)) != 0) return (ret); if (*eofp) return (0); /* * If the read was successful, but we can't read a full header, assume * we've hit EOF. We can't check that the header has been partially * zeroed out, but it's unlikely that this is caused by a write failure * since the header is written as a single write call and it's less * than sector. */ if (nr < hdr->size) { *eofp = 1; return (0); } /* Check the HDR. */ if ((ret = __log_c_hdrchk(logc, lsn, hdr, eofp)) != 0) return (ret); if (*eofp) return (0); /* * Regardless of how we return, the previous contents of the cursor's * buffer are useless -- trash it. */ logc->bp_rlen = 0; /* * Otherwise, we now (finally!) know how big the record is. (Maybe * we should have just stuck the length of the record into the LSN!?) * Make sure we have enough space. */ if (logc->bp_size <= hdr->len) { len = (size_t)DB_ALIGN(hdr->len * 2, 128); if ((ret = __os_realloc(dbenv, len, &logc->bp)) != 0) return (ret); logc->bp_size = (u_int32_t)len; } /* * If we're moving forward in the log file, read this record in at the * beginning of the buffer. Otherwise, read this record in at the end * of the buffer, making sure we don't try and read before the start * of the file. (We prefer positioning at the end because transaction * aborts use DB_SET to move backward through the log and we might get * lucky.) * * Read a buffer's worth, without reading past the logical EOF. The * last_lsn may be a zero LSN, but that's OK, the test works anyway. */ if (flags == DB_FIRST || flags == DB_NEXT) offset = lsn->offset; else if (lsn->offset + hdr->len < logc->bp_size) offset = 0; else offset = (lsn->offset + hdr->len) - logc->bp_size; nr = logc->bp_size; if (lsn->file == last_lsn->file && offset + nr >= last_lsn->offset) nr = last_lsn->offset - offset; if ((ret = __log_c_io(logc, lsn->file, offset, logc->bp, &nr, eofp)) != 0) return (ret); /* * We should have at least gotten the bytes up-to-and-including the * record we're reading. */ if (nr < (lsn->offset + hdr->len) - offset) return (__log_c_shortread(logc, lsn, 1)); /* * Set up the return information. * * !!! * No need to set the bp_lsn.file field, __log_c_io set it for us. */ logc->bp_rlen = (u_int32_t)nr; logc->bp_lsn.offset = offset; *pp = logc->bp + (lsn->offset - offset); return (0);}/* * __log_c_hdrchk -- * * Check for corrupted HDRs before we use them to allocate memory or find * records. * * If the log files were pre-allocated, a zero-filled HDR structure is the * logical file end. However, we can see buffers filled with 0's during * recovery, too (because multiple log buffers were written asynchronously, * and one made it to disk before a different one that logically precedes * it in the log file. * * Check for impossibly large records. The malloc should fail later, but we * have customers that run mallocs that treat all allocation failures as fatal * errors. * * Note that none of this is necessarily something awful happening. We let * the application hand us any LSN they want, and it could be a pointer into * the middle of a log record, there's no way to tell. */static int__log_c_hdrchk(logc, lsn, hdr, eofp) DB_LOGC *logc; DB_LSN *lsn; HDR *hdr; int *eofp;{ DB_ENV *dbenv; int ret; dbenv = logc->dbenv; /* * Check EOF before we do any other processing. */ if (eofp != NULL) { if (hdr->prev == 0 && hdr->chksum[0] == 0 && hdr->len == 0) { *eofp = 1; return (0); } *eofp = 0; } /* * Sanity check the log record's size. * We must check it after "virtual" EOF above. */ if (hdr->len <= hdr->size) goto err; /* * If the cursor's max-record value isn't yet set, it means we aren't * reading these records from a log file and no check is necessary. */ if (logc->bp_maxrec != 0 && hdr->len > logc->bp_maxrec) { /* * If we fail the check, there's the pathological case that * we're reading the last file, it's growing, and our initial * check information was wrong. Get it again, to be sure. */ if ((ret = __log_c_set_maxrec(logc, NULL)) != 0) { __db_err(dbenv, "DB_LOGC->get: %s", db_strerror(ret)); return (ret); } if (logc->bp_maxrec != 0 && hdr->len > logc->bp_maxrec) goto err; } return (0);err: if (!F_ISSET(logc, DB_LOG_SILENT_ERR)) __db_err(dbenv, "DB_LOGC->get: LSN %lu/%lu: invalid log record header", (u_long)lsn->file, (u_long)lsn->offset); return (EIO);}/* * __log_c_io -- * Read records from a log file. */static int__log_c_io(logc, fnum, offset, p, nrp, eofp) DB_LOGC *logc; u_int32_t fnum, offset; void *p; size_t *nrp; int *eofp;{ DB_ENV *dbenv; DB_LOG *dblp; int ret; char *np; dbenv = logc->dbenv; dblp = dbenv->lg_handle; /* * If we've switched files, discard the current file handle and acquire * a new one. */ if (logc->c_fhp != NULL && logc->bp_lsn.file != fnum) { ret = __os_closehandle(dbenv, logc->c_fhp); logc->c_fhp = NULL; logc->bp_lsn.file = 0; if (ret != 0) return (ret); } if (logc->c_fhp == NULL) { if ((ret = __log_name(dblp, fnum, &np, &logc->c_fhp, DB_OSO_RDONLY | DB_OSO_SEQ)) != 0) { /* * If we're allowed to return EOF, assume that's the * problem, set the EOF status flag and return 0. */ if (eofp != NULL) { *eofp = 1; ret = 0; } else if (!F_ISSET(logc, DB_LOG_SILENT_ERR)) __db_err(dbenv, "DB_LOGC->get: %s: %s", np, db_strerror(ret)); __os_free(dbenv, np); return (ret); } if ((ret = __log_c_set_maxrec(logc, np)) != 0) { __db_err(dbenv, "DB_LOGC->get: %s: %s", np, db_strerror(ret)); __os_free(dbenv, np); return (ret); } __os_free(dbenv, np); logc->bp_lsn.file = fnum; } /* Seek to the record's offset. */ if ((ret = __os_seek(dbenv, logc->c_fhp, 0, 0, offset, 0, DB_OS_SEEK_SET)) != 0) { if (!F_ISSET(logc, DB_LOG_SILENT_ERR)) __db_err(dbenv, "DB_LOGC->get: LSN: %lu/%lu: seek: %s", (u_long)fnum, (u_long)offset, db_strerror(ret)); return (ret); } /* Read the data. */ if ((ret = __os_read(dbenv, logc->c_fhp, p, *nrp, nrp)) != 0) { if (!F_ISSET(logc, DB_LOG_SILENT_ERR)) __db_err(dbenv, "DB_LOGC->get: LSN: %lu/%lu: read: %s", (u_long)fnum, (u_long)offset, db_strerror(ret)); return (ret); } return (0);}/* * __log_c_shortread -- * Read was short -- return a consistent error message and error. */static int__log_c_shortread(logc, lsn, check_silent) DB_LOGC *logc; DB_LSN *lsn; int check_silent;{ if (!check_silent || !F_ISSET(logc, DB_LOG_SILENT_ERR)) __db_err(logc->dbenv, "DB_LOGC->get: LSN: %lu/%lu: short read", (u_long)lsn->file, (u_long)lsn->offset); return (EIO);}/* * __log_c_set_maxrec -- * Bound the maximum log record size in a log file. */static int__log_c_set_maxrec(logc, np) DB_LOGC *logc; char *np;{ DB_ENV *dbenv; DB_LOG *dblp; LOG *lp; u_int32_t mbytes, bytes; int ret; dbenv = logc->dbenv; dblp = dbenv->lg_handle; /* * We don't want to try and allocate huge chunks of memory because * applications with error-checking malloc's often consider that a * hard failure. If we're about to look at a corrupted record with * a bizarre size, we need to know before trying to allocate space * to hold it. We could read the persistent data at the beginning * of the file but that's hard -- we may have to decrypt it, checksum * it and so on. Stat the file instead. */ if (logc->c_fhp != NULL) { if ((ret = __os_ioinfo(dbenv, np, logc->c_fhp, &mbytes, &bytes, NULL)) != 0) return (ret); if (logc->bp_maxrec < (mbytes * MEGABYTE + bytes)) logc->bp_maxrec = mbytes * MEGABYTE + bytes; } /* * If reading from the log file currently being written, we could get * an incorrect size, that is, if the cursor was opened on the file * when it had only a few hundred bytes, and then the cursor used to * move forward in the file, after more log records were written, the * original stat value would be wrong. Use the maximum of the current * log file size and the size of the buffer -- that should represent * the max of any log record currently in the file. * * The log buffer size is set when the environment is opened and never * changed, we don't need a lock on it. */ lp = dblp->reginfo.primary; if (logc->bp_maxrec < lp->buffer_size) logc->bp_maxrec = lp->buffer_size; return (0);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -