📄 journal.c
字号:
* by stepping header.begin forward to the first addressable * transaction. Also purge them from the index. */ if (! JOURNAL_EMPTY(&j->header)) { while (! DNS_SERIAL_GT(j->x.pos[1].serial, j->header.begin.serial)) { CHECK(journal_next(j, &j->header.begin)); } index_invalidate(j, j->x.pos[1].serial); }#ifdef notyet if (DNS_SERIAL_GT(last_dumped_serial, j->x.pos[1].serial)) { force_dump(...); }#endif /* * Commit the transaction data to stable storage. */ CHECK(journal_fsync(j)); /* * Update the transaction header. */ CHECK(journal_seek(j, j->x.pos[0].offset)); CHECK(journal_write_xhdr(j, (j->x.pos[1].offset - j->x.pos[0].offset) - sizeof(journal_rawxhdr_t), j->x.pos[0].serial, j->x.pos[1].serial)); /* * Update the journal header. */ if (JOURNAL_EMPTY(&j->header)) { j->header.begin = j->x.pos[0]; } j->header.end = j->x.pos[1]; journal_header_encode(&j->header, &rawheader); CHECK(journal_seek(j, 0)); CHECK(journal_write(j, &rawheader, sizeof(rawheader))); /* * Update the index. */ index_add(j, &j->x.pos[0]); /* * Convert the index into on-disk format and write * it to disk. */ CHECK(index_to_disk(j)); /* * Commit the header to stable storage. */ CHECK(journal_fsync(j)); /* * We no longer have a transaction open. */ j->state = JOURNAL_STATE_WRITE; result = ISC_R_SUCCESS; failure: return (result);}isc_result_tdns_journal_write_transaction(dns_journal_t *j, dns_diff_t *diff) { isc_result_t result; CHECK(dns_diff_sort(diff, ixfr_order)); CHECK(dns_journal_begin_transaction(j)); CHECK(dns_journal_writediff(j, diff)); CHECK(dns_journal_commit(j)); result = ISC_R_SUCCESS; failure: return (result);}voiddns_journal_destroy(dns_journal_t **journalp) { dns_journal_t *j = *journalp; REQUIRE(DNS_JOURNAL_VALID(j)); j->it.result = ISC_R_FAILURE; dns_name_invalidate(&j->it.name); dns_decompress_invalidate(&j->it.dctx); if (j->rawindex != NULL) isc_mem_put(j->mctx, j->rawindex, j->header.index_size * sizeof(journal_rawpos_t)); if (j->index != NULL) isc_mem_put(j->mctx, j->index, j->header.index_size * sizeof(journal_pos_t)); if (j->it.target.base != NULL) isc_mem_put(j->mctx, j->it.target.base, j->it.target.length); if (j->it.source.base != NULL) isc_mem_put(j->mctx, j->it.source.base, j->it.source.length); if (j->fp != NULL) (void)isc_stdio_close(j->fp); j->magic = 0; isc_mem_put(j->mctx, j, sizeof(*j)); *journalp = NULL;}/* * Roll the open journal 'j' into the database 'db'. * A new database version will be created. *//* XXX Share code with incoming IXFR? */static isc_result_troll_forward(dns_journal_t *j, dns_db_t *db) { isc_buffer_t source; /* Transaction data from disk */ isc_buffer_t target; /* Ditto after _fromwire check */ isc_uint32_t db_serial; /* Database SOA serial */ isc_uint32_t end_serial; /* Last journal SOA serial */ isc_result_t result; dns_dbversion_t *ver = NULL; journal_pos_t pos; dns_diff_t diff; unsigned int n_soa = 0; unsigned int n_put = 0; REQUIRE(DNS_JOURNAL_VALID(j)); REQUIRE(DNS_DB_VALID(db)); dns_diff_init(j->mctx, &diff); /* * Set up empty initial buffers for uncheched and checked * wire format transaction data. They will be reallocated * later. */ isc_buffer_init(&source, NULL, 0); isc_buffer_init(&target, NULL, 0); /* * Create the new database version. */ CHECK(dns_db_newversion(db, &ver)); /* * Get the current database SOA serial number. */ CHECK(dns_db_getsoaserial(db, ver, &db_serial)); /* * Locate a journal entry for the current database serial. */ CHECK(journal_find(j, db_serial, &pos)); /* * XXX do more drastic things, like marking zone stale, * if this fails? */ /* * XXXRTH The zone code should probably mark the zone as bad and * scream loudly into the log if this is a dynamic update * log reply that failed. */ end_serial = dns_journal_last_serial(j); if (db_serial == end_serial) CHECK(DNS_R_UPTODATE); CHECK(dns_journal_iter_init(j, db_serial, end_serial)); for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS; result = dns_journal_next_rr(j)) { dns_name_t *name; isc_uint32_t ttl; dns_rdata_t *rdata; dns_difftuple_t *tuple = NULL; name = NULL; rdata = NULL; dns_journal_current_rr(j, &name, &ttl, &rdata); if (rdata->type == dns_rdatatype_soa) { n_soa++; if (n_soa == 2) db_serial = j->it.current_serial; } if (n_soa == 3) n_soa = 1; if (n_soa == 0) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "%s: journal file corrupt: missing " "initial SOA", j->filename); FAIL(ISC_R_UNEXPECTED); } CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD, name, ttl, rdata, &tuple)); dns_diff_append(&diff, &tuple); if (++n_put > 100) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "applying diff to database (%u)", db_serial); (void)dns_diff_print(&diff, NULL); CHECK(dns_diff_apply(&diff, db, ver)); dns_diff_clear(&diff); n_put = 0; } } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; CHECK(result); if (n_put != 0) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "applying final diff to database (%u)", db_serial); (void)dns_diff_print(&diff, NULL); CHECK(dns_diff_apply(&diff, db, ver)); dns_diff_clear(&diff); } failure: if (ver != NULL) dns_db_closeversion(db, &ver, result == ISC_R_SUCCESS ? ISC_TRUE : ISC_FALSE); if (source.base != NULL) isc_mem_put(j->mctx, source.base, source.length); if (target.base != NULL) isc_mem_put(j->mctx, target.base, target.length); dns_diff_clear(&diff); return (result);}isc_result_tdns_journal_rollforward(isc_mem_t *mctx, dns_db_t *db, const char *filename) { dns_journal_t *j; isc_result_t result; REQUIRE(DNS_DB_VALID(db)); REQUIRE(filename != NULL); j = NULL; result = dns_journal_open(mctx, filename, ISC_FALSE, &j); if (result == ISC_R_NOTFOUND) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file, but that's OK"); return (DNS_R_NOJOURNAL); } if (result != ISC_R_SUCCESS) return (result); if (JOURNAL_EMPTY(&j->header)) result = DNS_R_UPTODATE; else result = roll_forward(j, db); dns_journal_destroy(&j); return (result);}isc_result_tdns_journal_print(isc_mem_t *mctx, const char *filename, FILE *file) { dns_journal_t *j; isc_buffer_t source; /* Transaction data from disk */ isc_buffer_t target; /* Ditto after _fromwire check */ isc_uint32_t start_serial; /* Database SOA serial */ isc_uint32_t end_serial; /* Last journal SOA serial */ isc_result_t result; dns_diff_t diff; unsigned int n_soa = 0; unsigned int n_put = 0; REQUIRE(filename != NULL); j = NULL; result = dns_journal_open(mctx, filename, ISC_FALSE, &j); if (result == ISC_R_NOTFOUND) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no journal file"); return (DNS_R_NOJOURNAL); } if (result != ISC_R_SUCCESS) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "journal open failure"); return (result); } dns_diff_init(j->mctx, &diff); /* * Set up empty initial buffers for uncheched and checked * wire format transaction data. They will be reallocated * later. */ isc_buffer_init(&source, NULL, 0); isc_buffer_init(&target, NULL, 0); start_serial = dns_journal_first_serial(j); end_serial = dns_journal_last_serial(j); CHECK(dns_journal_iter_init(j, start_serial, end_serial)); for (result = dns_journal_first_rr(j); result == ISC_R_SUCCESS; result = dns_journal_next_rr(j)) { dns_name_t *name; isc_uint32_t ttl; dns_rdata_t *rdata; dns_difftuple_t *tuple = NULL; name = NULL; rdata = NULL; dns_journal_current_rr(j, &name, &ttl, &rdata); if (rdata->type == dns_rdatatype_soa) n_soa++; if (n_soa == 3) n_soa = 1; if (n_soa == 0) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "%s: journal file corrupt: missing " "initial SOA", j->filename); FAIL(ISC_R_UNEXPECTED); } CHECK(dns_difftuple_create(diff.mctx, n_soa == 1 ? DNS_DIFFOP_DEL : DNS_DIFFOP_ADD, name, ttl, rdata, &tuple)); dns_diff_append(&diff, &tuple); if (++n_put > 100) { result = dns_diff_print(&diff, file); dns_diff_clear(&diff); n_put = 0; if (result != ISC_R_SUCCESS) break; } } if (result == ISC_R_NOMORE) result = ISC_R_SUCCESS; CHECK(result); if (n_put != 0) { result = dns_diff_print(&diff, file); dns_diff_clear(&diff); } goto cleanup; failure: isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "%s: cannot print: journal file corrupt", j->filename); cleanup: if (source.base != NULL) isc_mem_put(j->mctx, source.base, source.length); if (target.base != NULL) isc_mem_put(j->mctx, target.base, target.length); dns_diff_clear(&diff); dns_journal_destroy(&j); return (result);}/**************************************************************************//* * Miscellaneous accessors. */isc_uint32_t dns_journal_first_serial(dns_journal_t *j) { return (j->header.begin.serial);}isc_uint32_t dns_journal_last_serial(dns_journal_t *j) { return (j->header.end.serial);}/**************************************************************************//* * Iteration support. * * When serving an outgoing IXFR, we transmit a part the journal starting * at the serial number in the IXFR request and ending at the serial * number that is current when the IXFR request arrives. The ending * serial number is not necessarily at the end of the journal: * the journal may grow while the IXFR is in progress, but we stop * when we reach the serial number that was current when the IXFR started. */static isc_result_t read_one_rr(dns_journal_t *j);/* * Make sure the buffer 'b' is has at least 'size' bytes * allocated, and clear it. * * Requires: * Either b->base is NULL, or it points to b->length bytes of memory * previously allocated by isc_mem_get(). */static isc_result_tsize_buffer(isc_mem_t *mctx, isc_buffer_t *b, unsigned size) { if (b->length < size) { void *mem = isc_mem_get(mctx, size); if (mem == NULL) return (ISC_R_NOMEMORY); if (b->base != NULL) isc_mem_put(mctx, b->base, b->length); b->base = mem; b->length = size; } isc_buffer_clear(b); return (ISC_R_SUCCESS);}isc_result_tdns_journal_iter_init(dns_journal_t *j, isc_uint32_t begin_serial, isc_uint32_t end_serial){ isc_result_t result; CHECK(journal_find(j, begin_serial, &j->it.bpos)); INSIST(j->it.bpos.serial == begin_serial); CHECK(journal_find(j, end_serial, &j->it.epos)); INSIST(j->it.epos.serial == end_serial); result = ISC_R_SUCCESS; failure: j->it.result = result; return (j->it.result);}isc_result_tdns_journal_first_rr(dns_journal_t *j) { isc_result_t result; /* * Seek to the beginning of the first transaction we are * interested in. */ CHECK(journal_seek(j, j->it.bpos.offset)); j->it.current_serial = j->it.bpos.serial; j->it.xsize = 0; /* We have no transaction data yet... */ j->it.xpos = 0; /* ...and haven't used any of it. */ return (read_one_rr(j)); failure: return (result);}static isc_result_tread_one_rr(dns_journal_t *j) { isc_result_t result; dns_rdatatype_t rdtype; dns_rdataclass_t rdclass; unsigned int rdlen; isc_uint32_t ttl; journal_xhdr_t xhdr; journal_rrhdr_t rrhdr; INSIST(j->offset <= j->it.epos.offset); if (j->offset == j->it.epos.offset) return (ISC_R_NOMORE); if (j->it.xpos == j->it.xsize) { /* * We are at a transaction boundary. * Read another transaction header. */ CHECK(journal_read_xhdr(j, &xhdr)); if (xhdr.size == 0) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "journal corrupt: empty transaction"); FAIL(ISC_R_UNEXPECTED); } if (xhdr.serial0 != j->it.current_serial) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "%s: journal file corrupt: " "expected serial %u, got %u", j->filename, j->it.current_serial, xhdr.serial0); FAIL(ISC_R_UNEXPECTED); } j->it.xsize = xhdr.size; j->it.xpos = 0; } /* * Read an RR. */ result = journal_read_rrhdr(j, &rrhdr); /* * Perform a sanity check on the journal RR size. * The smallest possible RR has a 1-byte owner name * and a 10-byte header. The largest possible * RR has 65535 bytes of data, a header, and a maximum- * size owner name, well below 70 k total. */ if (rrhdr.size < 1+10 || rrhdr.size > 70000) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "%s: journal corrupt: impossible RR size " "(%d bytes)", j->filename, rrhdr.size); FAIL(ISC_R_UNEXPECTED); } CHECK(size_buffer(j->mctx, &j->it.source, rrhdr.size)); CHECK(journal_read(j, j->it.source.base, rrhdr.size)); isc_buffer_add(&j->it.source, rrhdr.size); /* * The target buffer is made the same size * as the source buffer, with the assumption that when * no compression in present, the output of dns_*_fromwire() * is no larger than the input. */ CHECK(size_buffer(j->mctx, &j->it.target, rrhdr.size)); /* * Parse the owner name. We don't know where it * ends yet, so we make the entire "remaining" * part of the buffer "active". */ isc_buffer_setactive(&j->it.source, j->it.source.used - j->it.source.current); CHECK(dns_name_fromwire(&j->it.name, &j->it.source,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -