mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 14:35:26 +00:00
2224. [bug] Defer journal compaction if a xfrin is in progress.
[RT #17119] 2223. [bug] Make a new journal when compacting. [RT #17119]
This commit is contained in:
5
CHANGES
5
CHANGES
@@ -1,3 +1,8 @@
|
|||||||
|
2224. [bug] Defer journal compaction if a xfrin is in progress.
|
||||||
|
[RT #17119]
|
||||||
|
|
||||||
|
2223. [bug] Make a new journal when compacting. [RT #17119]
|
||||||
|
|
||||||
2222. [func] named-checkconf now checks server key references.
|
2222. [func] named-checkconf now checks server key references.
|
||||||
[RT #17097]
|
[RT #17097]
|
||||||
|
|
||||||
|
@@ -15,12 +15,13 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: journal.c,v 1.96 2007/06/19 23:47:16 tbox Exp $ */
|
/* $Id: journal.c,v 1.97 2007/08/30 05:08:42 marka Exp $ */
|
||||||
|
|
||||||
#include <config.h>
|
#include <config.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
#include <isc/file.h>
|
#include <isc/file.h>
|
||||||
#include <isc/mem.h>
|
#include <isc/mem.h>
|
||||||
@@ -670,7 +671,23 @@ journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
|
|||||||
isc_result_t
|
isc_result_t
|
||||||
dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
|
dns_journal_open(isc_mem_t *mctx, const char *filename, isc_boolean_t write,
|
||||||
dns_journal_t **journalp) {
|
dns_journal_t **journalp) {
|
||||||
return (journal_open(mctx, filename, write, write, journalp));
|
isc_result_t result;
|
||||||
|
int len;
|
||||||
|
char backup[1024];
|
||||||
|
|
||||||
|
result = journal_open(mctx, filename, write, write, journalp);
|
||||||
|
if (result == ISC_R_NOTFOUND) {
|
||||||
|
len = strlen(filename);
|
||||||
|
if (len > 4 && strcmp(filename + len - 4, ".jnl") == 0)
|
||||||
|
len -= 4;
|
||||||
|
|
||||||
|
result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk",
|
||||||
|
len, filename);
|
||||||
|
if (result != ISC_R_SUCCESS)
|
||||||
|
return (result);
|
||||||
|
result = journal_open(mctx, backup, write, write, journalp);
|
||||||
|
}
|
||||||
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -1927,6 +1944,7 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
|
|||||||
journal_pos_t best_guess;
|
journal_pos_t best_guess;
|
||||||
journal_pos_t current_pos;
|
journal_pos_t current_pos;
|
||||||
dns_journal_t *j = NULL;
|
dns_journal_t *j = NULL;
|
||||||
|
dns_journal_t *new = NULL;
|
||||||
journal_rawheader_t rawheader;
|
journal_rawheader_t rawheader;
|
||||||
unsigned int copy_length;
|
unsigned int copy_length;
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
@@ -1934,8 +1952,31 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
|
|||||||
unsigned int size = 0;
|
unsigned int size = 0;
|
||||||
isc_result_t result;
|
isc_result_t result;
|
||||||
unsigned int indexend;
|
unsigned int indexend;
|
||||||
|
char newname[1024];
|
||||||
|
char backup[1024];
|
||||||
|
isc_boolean_t is_backup = ISC_FALSE;
|
||||||
|
|
||||||
CHECK(journal_open(mctx, filename, ISC_TRUE, ISC_FALSE, &j));
|
len = strlen(filename);
|
||||||
|
if (len > 4 && strcmp(filename + len - 4, ".jnl") == 0)
|
||||||
|
len -= 4;
|
||||||
|
|
||||||
|
result = isc_string_printf(newname, sizeof(newname), "%.*s.jnw",
|
||||||
|
len, filename);
|
||||||
|
if (result != ISC_R_SUCCESS)
|
||||||
|
return (result);
|
||||||
|
|
||||||
|
result = isc_string_printf(backup, sizeof(backup), "%.*s.jbk",
|
||||||
|
len, filename);
|
||||||
|
if (result != ISC_R_SUCCESS)
|
||||||
|
return (result);
|
||||||
|
|
||||||
|
result = journal_open(mctx, filename, ISC_FALSE, ISC_FALSE, &j);
|
||||||
|
if (result == ISC_R_NOTFOUND) {
|
||||||
|
is_backup = ISC_TRUE;
|
||||||
|
result = journal_open(mctx, backup, ISC_FALSE, ISC_FALSE, &j);
|
||||||
|
}
|
||||||
|
if (result != ISC_R_SUCCESS)
|
||||||
|
return (result);
|
||||||
|
|
||||||
if (JOURNAL_EMPTY(&j->header)) {
|
if (JOURNAL_EMPTY(&j->header)) {
|
||||||
dns_journal_destroy(&j);
|
dns_journal_destroy(&j);
|
||||||
@@ -1964,6 +2005,8 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
|
|||||||
return (ISC_R_SUCCESS);
|
return (ISC_R_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK(journal_open(mctx, newname, ISC_TRUE, ISC_TRUE, &new));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove overhead so space test below can succeed.
|
* Remove overhead so space test below can succeed.
|
||||||
*/
|
*/
|
||||||
@@ -2003,47 +2046,12 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
|
|||||||
CHECK(journal_next(j, &best_guess));
|
CHECK(journal_next(j, &best_guess));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enough space to proceed?
|
* We should now be roughly half target_size provided
|
||||||
|
* we did not reach 'serial'. If not we will just copy
|
||||||
|
* all uncommitted deltas regardless of the size.
|
||||||
*/
|
*/
|
||||||
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;
|
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) {
|
if (copy_length != 0) {
|
||||||
/*
|
/*
|
||||||
* Copy best_guess to end into space just freed.
|
* Copy best_guess to end into space just freed.
|
||||||
@@ -2057,56 +2065,90 @@ dns_journal_compact(isc_mem_t *mctx, char *filename, isc_uint32_t serial,
|
|||||||
goto failure;
|
goto failure;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CHECK(journal_seek(j, best_guess.offset));
|
||||||
|
CHECK(journal_seek(new, indexend));
|
||||||
for (i = 0; i < copy_length; i += size) {
|
for (i = 0; i < copy_length; i += size) {
|
||||||
len = (copy_length - i) > size ? size :
|
len = (copy_length - i) > size ? size :
|
||||||
(copy_length - i);
|
(copy_length - i);
|
||||||
CHECK(journal_seek(j, best_guess.offset + i));
|
|
||||||
CHECK(journal_read(j, buf, len));
|
CHECK(journal_read(j, buf, len));
|
||||||
CHECK(journal_seek(j, indexend + i));
|
CHECK(journal_write(new, buf, len));
|
||||||
CHECK(journal_write(j, buf, len));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CHECK(journal_fsync(j));
|
CHECK(journal_fsync(new));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute new header.
|
* Compute new header.
|
||||||
*/
|
*/
|
||||||
j->header.begin.offset = indexend;
|
new->header.begin.serial = best_guess.serial;
|
||||||
j->header.end.offset = indexend + copy_length;
|
new->header.begin.offset = indexend;
|
||||||
|
new->header.end.serial = j->header.end.serial;
|
||||||
|
new->header.end.offset = indexend + copy_length;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the journal header.
|
* Update the journal header.
|
||||||
*/
|
*/
|
||||||
journal_header_encode(&j->header, &rawheader);
|
journal_header_encode(&new->header, &rawheader);
|
||||||
CHECK(journal_seek(j, 0));
|
CHECK(journal_seek(new, 0));
|
||||||
CHECK(journal_write(j, &rawheader, sizeof(rawheader)));
|
CHECK(journal_write(new, &rawheader, sizeof(rawheader)));
|
||||||
CHECK(journal_fsync(j));
|
CHECK(journal_fsync(new));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build new index.
|
* Build new index.
|
||||||
*/
|
*/
|
||||||
current_pos = j->header.begin;
|
current_pos = new->header.begin;
|
||||||
while (current_pos.serial != j->header.end.serial) {
|
while (current_pos.serial != new->header.end.serial) {
|
||||||
index_add(j, ¤t_pos);
|
index_add(new, ¤t_pos);
|
||||||
CHECK(journal_next(j, ¤t_pos));
|
CHECK(journal_next(new, ¤t_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write index.
|
* Write index.
|
||||||
*/
|
*/
|
||||||
CHECK(index_to_disk(j));
|
CHECK(index_to_disk(new));
|
||||||
CHECK(journal_fsync(j));
|
CHECK(journal_fsync(new));
|
||||||
|
|
||||||
indexend = j->header.end.offset;
|
indexend = new->header.end.offset;
|
||||||
}
|
}
|
||||||
|
dns_journal_destroy(&new);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* With a UFS file system this should just succeed and be atomic.
|
||||||
|
* Any IXFR outs will just continue and the old journal will be
|
||||||
|
* removed on final close.
|
||||||
|
*
|
||||||
|
* With MSDOS / NTFS we need to do a two stage rename triggered
|
||||||
|
* bu EEXISTS. Hopefully all IXFR's that were active at the last
|
||||||
|
* rename are now complete.
|
||||||
|
*/
|
||||||
|
if (rename(newname, filename) == -1) {
|
||||||
|
if (errno == EACCES && !is_backup) {
|
||||||
|
result = isc_file_remove(backup);
|
||||||
|
if (result != ISC_R_SUCCESS &&
|
||||||
|
result != ISC_R_FILENOTFOUND)
|
||||||
|
goto failure;
|
||||||
|
if (rename(filename, backup) == -1)
|
||||||
|
goto maperrno;
|
||||||
|
if (rename(newname, filename) == -1)
|
||||||
|
goto maperrno;
|
||||||
|
(void)isc_file_remove(backup);
|
||||||
|
} else {
|
||||||
|
maperrno:
|
||||||
|
result = ISC_R_FAILURE;
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
dns_journal_destroy(&j);
|
dns_journal_destroy(&j);
|
||||||
(void)isc_file_truncate(filename, (isc_offset_t)indexend);
|
|
||||||
result = ISC_R_SUCCESS;
|
result = ISC_R_SUCCESS;
|
||||||
|
|
||||||
failure:
|
failure:
|
||||||
|
(void)isc_file_remove(newname);
|
||||||
if (buf != NULL)
|
if (buf != NULL)
|
||||||
isc_mem_put(mctx, buf, size);
|
isc_mem_put(mctx, buf, size);
|
||||||
if (j != NULL)
|
if (j != NULL)
|
||||||
dns_journal_destroy(&j);
|
dns_journal_destroy(&j);
|
||||||
|
if (new != NULL)
|
||||||
|
dns_journal_destroy(&new);
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* PERFORMANCE OF THIS SOFTWARE.
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* $Id: zone.c,v 1.466 2007/08/27 03:32:27 marka Exp $ */
|
/* $Id: zone.c,v 1.467 2007/08/30 05:08:42 marka Exp $ */
|
||||||
|
|
||||||
/*! \file */
|
/*! \file */
|
||||||
|
|
||||||
@@ -260,6 +260,11 @@ struct dns_zone {
|
|||||||
char * strname;
|
char * strname;
|
||||||
char * strrdclass;
|
char * strrdclass;
|
||||||
char * strviewname;
|
char * strviewname;
|
||||||
|
|
||||||
|
/*%
|
||||||
|
* Serial number for deferred journal compaction.
|
||||||
|
*/
|
||||||
|
isc_uint32_t compact_serial;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
|
#define DNS_ZONE_FLAG(z,f) (ISC_TF(((z)->flags & (f)) != 0))
|
||||||
@@ -305,6 +310,7 @@ struct dns_zone {
|
|||||||
#define DNS_ZONEFLG_NOEDNS 0x00400000U
|
#define DNS_ZONEFLG_NOEDNS 0x00400000U
|
||||||
#define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U
|
#define DNS_ZONEFLG_USEALTXFRSRC 0x00800000U
|
||||||
#define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U
|
#define DNS_ZONEFLG_SOABEFOREAXFR 0x01000000U
|
||||||
|
#define DNS_ZONEFLG_NEEDCOMPACT 0x02000000U
|
||||||
|
|
||||||
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
|
#define DNS_ZONE_OPTION(z,o) (((z)->options & (o)) != 0)
|
||||||
|
|
||||||
@@ -3274,6 +3280,9 @@ dump_done(void *arg, isc_result_t result) {
|
|||||||
dns_db_t *db;
|
dns_db_t *db;
|
||||||
dns_dbversion_t *version;
|
dns_dbversion_t *version;
|
||||||
isc_boolean_t again = ISC_FALSE;
|
isc_boolean_t again = ISC_FALSE;
|
||||||
|
isc_boolean_t compact = ISC_FALSE;
|
||||||
|
isc_uint32_t serial;
|
||||||
|
isc_result_t tresult;
|
||||||
|
|
||||||
REQUIRE(DNS_ZONE_VALID(zone));
|
REQUIRE(DNS_ZONE_VALID(zone));
|
||||||
|
|
||||||
@@ -3281,8 +3290,6 @@ dump_done(void *arg, isc_result_t result) {
|
|||||||
|
|
||||||
if (result == ISC_R_SUCCESS && zone->journal != NULL &&
|
if (result == ISC_R_SUCCESS && zone->journal != NULL &&
|
||||||
zone->journalsize != -1) {
|
zone->journalsize != -1) {
|
||||||
isc_uint32_t serial;
|
|
||||||
isc_result_t tresult;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We don't own these, zone->dctx must stay valid.
|
* We don't own these, zone->dctx must stay valid.
|
||||||
@@ -3291,7 +3298,11 @@ dump_done(void *arg, isc_result_t result) {
|
|||||||
version = dns_dumpctx_version(zone->dctx);
|
version = dns_dumpctx_version(zone->dctx);
|
||||||
|
|
||||||
tresult = dns_db_getsoaserial(db, version, &serial);
|
tresult = dns_db_getsoaserial(db, version, &serial);
|
||||||
if (tresult == ISC_R_SUCCESS) {
|
/*
|
||||||
|
* Note: we are task locked here so we can test
|
||||||
|
* zone->xfr safely.
|
||||||
|
*/
|
||||||
|
if (tresult == ISC_R_SUCCESS && zone->xfr == NULL) {
|
||||||
tresult = dns_journal_compact(zone->mctx,
|
tresult = dns_journal_compact(zone->mctx,
|
||||||
zone->journal,
|
zone->journal,
|
||||||
serial,
|
serial,
|
||||||
@@ -3310,11 +3321,16 @@ dump_done(void *arg, isc_result_t result) {
|
|||||||
dns_result_totext(tresult));
|
dns_result_totext(tresult));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
} else if (tresult == ISC_R_SUCCESS) {
|
||||||
|
compact = ISC_TRUE;
|
||||||
|
zone->compact_serial = serial;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LOCK_ZONE(zone);
|
LOCK_ZONE(zone);
|
||||||
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DUMPING);
|
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_DUMPING);
|
||||||
|
if (compact)
|
||||||
|
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT);
|
||||||
if (result != ISC_R_SUCCESS && result != ISC_R_CANCELED) {
|
if (result != ISC_R_SUCCESS && result != ISC_R_CANCELED) {
|
||||||
/*
|
/*
|
||||||
* Try again in a short while.
|
* Try again in a short while.
|
||||||
@@ -6809,6 +6825,30 @@ zone_xfrdone(dns_zone_t *zone, isc_result_t result) {
|
|||||||
if (zone->tsigkey != NULL)
|
if (zone->tsigkey != NULL)
|
||||||
dns_tsigkey_detach(&zone->tsigkey);
|
dns_tsigkey_detach(&zone->tsigkey);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Handle any deferred journal compaction.
|
||||||
|
*/
|
||||||
|
if (DNS_ZONE_FLAG(zone, DNS_ZONEFLG_NEEDCOMPACT)) {
|
||||||
|
result = dns_journal_compact(zone->mctx, zone->journal,
|
||||||
|
zone->compact_serial,
|
||||||
|
zone->journalsize);
|
||||||
|
switch (result) {
|
||||||
|
case ISC_R_SUCCESS:
|
||||||
|
case ISC_R_NOSPACE:
|
||||||
|
case ISC_R_NOTFOUND:
|
||||||
|
dns_zone_log(zone, ISC_LOG_DEBUG(3),
|
||||||
|
"dns_journal_compact: %s",
|
||||||
|
dns_result_totext(result));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
dns_zone_log(zone, ISC_LOG_ERROR,
|
||||||
|
"dns_journal_compact failed: %s",
|
||||||
|
dns_result_totext(result));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
DNS_ZONE_CLRFLAG(zone, DNS_ZONEFLG_NEEDCOMPACT);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This transfer finishing freed up a transfer quota slot.
|
* This transfer finishing freed up a transfer quota slot.
|
||||||
* Let any other zones waiting for quota have it.
|
* Let any other zones waiting for quota have it.
|
||||||
|
Reference in New Issue
Block a user