📄 journal.c
字号:
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, &j->it.dctx, ISC_FALSE, &j->it.target)); /* * Check that the RR header is there, and parse it. */ if (isc_buffer_remaininglength(&j->it.source) < 10) FAIL(DNS_R_FORMERR); rdtype = isc_buffer_getuint16(&j->it.source); rdclass = isc_buffer_getuint16(&j->it.source); ttl = isc_buffer_getuint32(&j->it.source); rdlen = isc_buffer_getuint16(&j->it.source); /* * Parse the rdata. */ isc_buffer_setactive(&j->it.source, rdlen); dns_rdata_reset(&j->it.rdata); CHECK(dns_rdata_fromwire(&j->it.rdata, rdclass, rdtype, &j->it.source, &j->it.dctx, ISC_FALSE, &j->it.target)); j->it.ttl = ttl; j->it.xpos += sizeof(journal_rawrrhdr_t) + rrhdr.size; if (rdtype == dns_rdatatype_soa) { /* XXX could do additional consistency checks here */ j->it.current_serial = dns_soa_getserial(&j->it.rdata); } result = ISC_R_SUCCESS; failure: j->it.result = result; return (result);}isc_result_tdns_journal_next_rr(dns_journal_t *j) { j->it.result = read_one_rr(j); return (j->it.result);}voiddns_journal_current_rr(dns_journal_t *j, dns_name_t **name, isc_uint32_t *ttl, dns_rdata_t **rdata){ REQUIRE(j->it.result == ISC_R_SUCCESS); *name = &j->it.name; *ttl = j->it.ttl; *rdata = &j->it.rdata;}/**************************************************************************//* * Generating diffs from databases *//* * Construct a diff containing all the RRs at the current name of the * database iterator 'dbit' in database 'db', version 'ver'. * Set '*name' to the current name, and append the diff to 'diff'. * All new tuples will have the operation 'op'. * * Requires: 'name' must have buffer large enough to hold the name. * Typically, a dns_fixedname_t would be used. */static isc_result_tget_name_diff(dns_db_t *db, dns_dbversion_t *ver, isc_stdtime_t now, dns_dbiterator_t *dbit, dns_name_t *name, dns_diffop_t op, dns_diff_t *diff){ isc_result_t result; dns_dbnode_t *node = NULL; dns_rdatasetiter_t *rdsiter = NULL; dns_difftuple_t *tuple = NULL; result = dns_dbiterator_current(dbit, &node, name); if (result != ISC_R_SUCCESS) return (result); result = dns_db_allrdatasets(db, node, ver, now, &rdsiter); if (result != ISC_R_SUCCESS) goto cleanup_node; for (result = dns_rdatasetiter_first(rdsiter); result == ISC_R_SUCCESS; result = dns_rdatasetiter_next(rdsiter)) { dns_rdataset_t rdataset; dns_rdataset_init(&rdataset); dns_rdatasetiter_current(rdsiter, &rdataset); for (result = dns_rdataset_first(&rdataset); result == ISC_R_SUCCESS; result = dns_rdataset_next(&rdataset)) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); result = dns_difftuple_create(diff->mctx, op, name, rdataset.ttl, &rdata, &tuple); if (result != ISC_R_SUCCESS) { dns_rdataset_disassociate(&rdataset); goto cleanup_iterator; } dns_diff_append(diff, &tuple); } dns_rdataset_disassociate(&rdataset); if (result != ISC_R_NOMORE) goto cleanup_iterator; } if (result != ISC_R_NOMORE) goto cleanup_iterator; result = ISC_R_SUCCESS; cleanup_iterator: dns_rdatasetiter_destroy(&rdsiter); cleanup_node: dns_db_detachnode(db, &node); return (result);}/* * Comparison function for use by dns_diff_subtract when sorting * the diffs to be subtracted. The sort keys are the rdata type * and the rdata itself. The owner name is ignored, because * it is known to be the same for all tuples. */static intrdata_order(const void *av, const void *bv) { dns_difftuple_t const * const *ap = av; dns_difftuple_t const * const *bp = bv; dns_difftuple_t const *a = *ap; dns_difftuple_t const *b = *bp; int r; r = (b->rdata.type - a->rdata.type); if (r != 0) return (r); r = dns_rdata_compare(&a->rdata, &b->rdata); return (r);}static isc_result_tdns_diff_subtract(dns_diff_t diff[2], dns_diff_t *r) { isc_result_t result; dns_difftuple_t *p[2]; int i, t; CHECK(dns_diff_sort(&diff[0], rdata_order)); CHECK(dns_diff_sort(&diff[1], rdata_order)); for (;;) { p[0] = ISC_LIST_HEAD(diff[0].tuples); p[1] = ISC_LIST_HEAD(diff[1].tuples); if (p[0] == NULL && p[1] == NULL) break; for (i = 0; i < 2; i++) if (p[!i] == NULL) { ISC_LIST_UNLINK(diff[i].tuples, p[i], link); ISC_LIST_APPEND(r->tuples, p[i], link); goto next; } t = rdata_order(&p[0], &p[1]); if (t < 0) { ISC_LIST_UNLINK(diff[0].tuples, p[0], link); ISC_LIST_APPEND(r->tuples, p[0], link); goto next; } if (t > 0) { ISC_LIST_UNLINK(diff[1].tuples, p[1], link); ISC_LIST_APPEND(r->tuples, p[1], link); goto next; } INSIST(t == 0); /* * Identical RRs in both databases; skip them both. */ for (i = 0; i < 2; i++) { ISC_LIST_UNLINK(diff[i].tuples, p[i], link); dns_difftuple_free(&p[i]); } next: ; } result = ISC_R_SUCCESS; failure: return (result);}/* * Compare the databases 'dba' and 'dbb' and generate a journal * entry containing the changes to make 'dba' from 'dbb' (note * the order). This journal entry will consist of a single, * possibly very large transaction. */isc_result_tdns_db_diff(isc_mem_t *mctx, dns_db_t *dba, dns_dbversion_t *dbvera, dns_db_t *dbb, dns_dbversion_t *dbverb, const char *journal_filename){ dns_db_t *db[2]; dns_dbversion_t *ver[2]; dns_dbiterator_t *dbit[2] = { NULL, NULL }; isc_boolean_t have[2] = { ISC_FALSE, ISC_FALSE }; dns_fixedname_t fixname[2]; isc_result_t result, itresult[2]; dns_diff_t diff[2], resultdiff; int i, t; dns_journal_t *journal = NULL; db[0] = dba, db[1] = dbb; ver[0] = dbvera, ver[1] = dbverb; dns_diff_init(mctx, &diff[0]); dns_diff_init(mctx, &diff[1]); dns_diff_init(mctx, &resultdiff); dns_fixedname_init(&fixname[0]); dns_fixedname_init(&fixname[1]); CHECK(dns_journal_open(mctx, journal_filename, ISC_TRUE, &journal)); CHECK(dns_db_createiterator(db[0], ISC_FALSE, &dbit[0])); CHECK(dns_db_createiterator(db[1], ISC_FALSE, &dbit[1])); itresult[0] = dns_dbiterator_first(dbit[0]); itresult[1] = dns_dbiterator_first(dbit[1]); for (;;) { for (i = 0; i < 2; i++) { if (! have[i] && itresult[i] == ISC_R_SUCCESS) { CHECK(get_name_diff(db[i], ver[i], 0, dbit[i], dns_fixedname_name(&fixname[i]), i == 0 ? DNS_DIFFOP_ADD : DNS_DIFFOP_DEL, &diff[i])); itresult[i] = dns_dbiterator_next(dbit[i]); have[i] = ISC_TRUE; } } if (! have[0] && ! have[1]) { INSIST(ISC_LIST_EMPTY(diff[0].tuples)); INSIST(ISC_LIST_EMPTY(diff[1].tuples)); break; } for (i = 0; i < 2; i++) { if (! have[!i]) { ISC_LIST_APPENDLIST(resultdiff.tuples, diff[i].tuples, link); INSIST(ISC_LIST_EMPTY(diff[i].tuples)); have[i] = ISC_FALSE; goto next; } } t = dns_name_compare(dns_fixedname_name(&fixname[0]), dns_fixedname_name(&fixname[1])); if (t < 0) { ISC_LIST_APPENDLIST(resultdiff.tuples, diff[0].tuples, link); INSIST(ISC_LIST_EMPTY(diff[0].tuples)); have[0] = ISC_FALSE; continue; } if (t > 0) { ISC_LIST_APPENDLIST(resultdiff.tuples, diff[1].tuples, link); INSIST(ISC_LIST_EMPTY(diff[1].tuples)); have[1] = ISC_FALSE; continue; } INSIST(t == 0); CHECK(dns_diff_subtract(diff, &resultdiff)); INSIST(ISC_LIST_EMPTY(diff[0].tuples)); INSIST(ISC_LIST_EMPTY(diff[1].tuples)); have[0] = have[1] = ISC_FALSE; next: ; } if (itresult[0] != ISC_R_NOMORE) FAIL(itresult[0]); if (itresult[1] != ISC_R_NOMORE) FAIL(itresult[1]); if (ISC_LIST_EMPTY(resultdiff.tuples)) { isc_log_write(JOURNAL_DEBUG_LOGARGS(3), "no changes"); } else { CHECK(dns_journal_write_transaction(journal, &resultdiff)); } INSIST(ISC_LIST_EMPTY(diff[0].tuples)); INSIST(ISC_LIST_EMPTY(diff[1].tuples)); dns_diff_clear(&resultdiff); failure: dns_dbiterator_destroy(&dbit[0]); dns_dbiterator_destroy(&dbit[1]); dns_journal_destroy(&journal); return (result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -