📄 journal.c
字号:
j->x.pos[j->x.n_soa].serial = dns_soa_getserial(&t->rdata); j->x.n_soa++; } size += sizeof(journal_rawrrhdr_t); size += t->name.length; /* XXX should have access macro? */ size += 10; size += t->rdata.length; } mem = isc_mem_get(j->mctx, size); if (mem == NULL) return (ISC_R_NOMEMORY); isc_buffer_init(&buffer, mem, size); /* * Pass 2. Write RRs to buffer. */ for (t = ISC_LIST_HEAD(diff->tuples); t != NULL; t = ISC_LIST_NEXT(t, link)) { /* * Write the RR header. */ isc_buffer_putuint32(&buffer, t->name.length + 10 + t->rdata.length); /* * Write the owner name, RR header, and RR data. */ isc_buffer_putmem(&buffer, t->name.ndata, t->name.length); isc_buffer_putuint16(&buffer, t->rdata.type); isc_buffer_putuint16(&buffer, t->rdata.rdclass); isc_buffer_putuint32(&buffer, t->ttl); INSIST(t->rdata.length < 65536); isc_buffer_putuint16(&buffer, (isc_uint16_t)t->rdata.length); INSIST(isc_buffer_availablelength(&buffer) >= t->rdata.length); isc_buffer_putmem(&buffer, t->rdata.data, t->rdata.length); } isc_buffer_usedregion(&buffer, &used); INSIST(used.length == size); j->x.pos[1].offset += used.length; /* * Write the buffer contents to the journal file. */ CHECK(journal_write(j, used.base, used.length)); result = ISC_R_SUCCESS; failure: if (mem != NULL) isc_mem_put(j->mctx, mem, size); return (result);}isc_result_tdns_journal_commit(dns_journal_t *j) { isc_result_t result; journal_rawheader_t rawheader; REQUIRE(DNS_JOURNAL_VALID(j)); REQUIRE(j->state == JOURNAL_STATE_TRANSACTION); /* * Perform some basic consistency checks. */ if (j->x.n_soa != 2) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "malformed transaction: %d SOAs", j->x.n_soa); return (ISC_R_UNEXPECTED); } if (! (DNS_SERIAL_GT(j->x.pos[1].serial, j->x.pos[0].serial) || (bind8_compat && j->x.pos[1].serial == j->x.pos[0].serial))) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "malformed transaction: serial number " "would decrease"); return (ISC_R_UNEXPECTED); } if (! JOURNAL_EMPTY(&j->header)) { if (j->x.pos[0].serial != j->header.end.serial) { isc_log_write(JOURNAL_COMMON_LOGARGS, ISC_LOG_ERROR, "malformed transaction: " "%s last serial %u != " "transaction first serial %u", j->filename, j->header.end.serial, j->x.pos[0].serial); return (ISC_R_UNEXPECTED); } } /* * Some old journal entries may become non-addressable * when we increment the current serial number. Purge them * 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. */ 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_write(j, j->rawindex, rawbytes)); } /* * 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 == 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"); 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"); 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -