📄 journal.c
字号:
&j->it.dctx, 0, &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, 0, &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]); result = dns_journal_open(mctx, journal_filename, ISC_TRUE, &journal); if (result != ISC_R_SUCCESS) return (result); result = dns_db_createiterator(db[0], ISC_FALSE, &dbit[0]); if (result != ISC_R_SUCCESS) goto cleanup_journal; result = dns_db_createiterator(db[1], ISC_FALSE, &dbit[1]); if (result != ISC_R_SUCCESS) goto cleanup_interator0; 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)); failure: dns_diff_clear(&resultdiff); dns_dbiterator_destroy(&dbit[1]); cleanup_interator0: dns_dbiterator_destroy(&dbit[0]); cleanup_journal: dns_journal_destroy(&journal); return (result);}isc_result_tdns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial, isc_uint32_t target_size){ unsigned int i; journal_pos_t best_guess; journal_pos_t current_pos; dns_journal_t *j = NULL; journal_rawheader_t rawheader; unsigned int copy_length; unsigned int len; char *buf = NULL; unsigned int size = 0; isc_result_t result; unsigned int indexend; CHECK(journal_open(mctx, filename, ISC_TRUE, ISC_FALSE, &j)); if (JOURNAL_EMPTY(&j->header)) { dns_journal_destroy(&j); return (ISC_R_SUCCESS); } if (DNS_SERIAL_GT(j->header.begin.serial, serial) || DNS_SERIAL_GT(serial, j->header.end.serial)) { dns_journal_destroy(&j); return (ISC_R_RANGE); } /* * Cope with very small target sizes. */ indexend = sizeof(journal_rawheader_t) + j->header.index_size * sizeof(journal_rawpos_t); if (target_size < indexend * 2) target_size = target_size/2 + indexend; /* * See if there is any work to do. */ if ((isc_uint32_t) j->header.end.offset < target_size) { dns_journal_destroy(&j); return (ISC_R_SUCCESS); } /* * Remove overhead so space test below can succeed. */ if (target_size >= indexend) target_size -= indexend; /* * Find if we can create enough free space. */ best_guess = j->header.begin; for (i = 0; i < j->header.index_size; i++) { if (POS_VALID(j->index[i]) && DNS_SERIAL_GE(serial, j->index[i].serial) && ((isc_uint32_t)(j->header.end.offset - j->index[i].offset) >= target_size / 2) && j->index[i].offset > best_guess.offset) best_guess = j->index[i]; } current_pos = best_guess; while (current_pos.serial != serial) { CHECK(journal_next(j, ¤t_pos)); if (current_pos.serial == j->header.end.serial) break; if (DNS_SERIAL_GE(serial, current_pos.serial) && ((isc_uint32_t)(j->header.end.offset - current_pos.offset) >= (target_size / 2)) && current_pos.offset > best_guess.offset) best_guess = current_pos; else break; } INSIST(best_guess.serial != j->header.end.serial); if (best_guess.serial != serial) CHECK(journal_next(j, &best_guess)); /* * Enough space to proceed? */ if ((isc_uint32_t) (j->header.end.offset - best_guess.offset) > (isc_uint32_t) (best_guess.offset - indexend)) { dns_journal_destroy(&j); return (ISC_R_NOSPACE); } copy_length = j->header.end.offset - best_guess.offset; /* * Invalidate entire index, will be rebuilt at end. */ for (i = 0; i < j->header.index_size; i++) { if (POS_VALID(j->index[i])) POS_INVALIDATE(j->index[i]); } /* * Convert the index into on-disk format and write * it to disk. */ CHECK(index_to_disk(j)); CHECK(journal_fsync(j)); /* * Update the journal header. */ if (copy_length == 0) { j->header.begin.serial = 0; j->header.end.serial = 0; j->header.begin.offset = 0; j->header.end.offset = 0; } else { j->header.begin = best_guess; } journal_header_encode(&j->header, &rawheader); CHECK(journal_seek(j, 0)); CHECK(journal_write(j, &rawheader, sizeof(rawheader))); CHECK(journal_fsync(j)); if (copy_length != 0) { /* * Copy best_guess to end into space just freed. */ size = 64*1024; if (copy_length < size) size = copy_length; buf = isc_mem_get(mctx, size); if (buf == NULL) { result = ISC_R_NOMEMORY; goto failure; } for (i = 0; i < copy_length; i += size) { len = (copy_length - i) > size ? size : (copy_length - i); CHECK(journal_seek(j, best_guess.offset + i)); CHECK(journal_read(j, buf, len)); CHECK(journal_seek(j, indexend + i)); CHECK(journal_write(j, buf, len)); } CHECK(journal_fsync(j)); /* * Compute new header. */ j->header.begin.offset = indexend; j->header.end.offset = indexend + copy_length; /* * Update the journal header. */ journal_header_encode(&j->header, &rawheader); CHECK(journal_seek(j, 0)); CHECK(journal_write(j, &rawheader, sizeof(rawheader))); CHECK(journal_fsync(j)); /* * Build new index. */ current_pos = j->header.begin; while (current_pos.serial != j->header.end.serial) { index_add(j, ¤t_pos); CHECK(journal_next(j, ¤t_pos)); } /* * Write index. */ CHECK(index_to_disk(j)); CHECK(journal_fsync(j)); indexend = j->header.end.offset; } dns_journal_destroy(&j); (void)isc_file_truncate(filename, (isc_offset_t)indexend); result = ISC_R_SUCCESS; failure: if (buf != NULL) isc_mem_put(mctx, buf, size); if (j != NULL) dns_journal_destroy(&j); return (result);}static isc_result_tindex_to_disk(dns_journal_t *j) { isc_result_t result = ISC_R_SUCCESS; if (j->header.index_size != 0) { unsigned int i; unsigned char *p; unsigned int rawbytes; rawbytes = j->header.index_size * sizeof(journal_rawpos_t); p = j->rawindex; for (i = 0; i < j->header.index_size; i++) { encode_uint32(j->index[i].serial, p); p += 4; encode_uint32(j->index[i].offset, p); p += 4; } INSIST(p == j->rawindex + rawbytes); CHECK(journal_seek(j, sizeof(journal_rawheader_t))); CHECK(journal_write(j, j->rawindex, rawbytes)); }failure: return (result);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -