void * signal_logger_handle_reopen_all_thread(void* ignored) { if(!dnscore_shuttingdown()) { log_debug("signal_logger_handle_reopen_all_thread: begin"); logger_reopen(); log_info("loggers reopened"); log_debug("signal_logger_handle_reopen_all_thread: end"); } pthread_exit(NULL); return NULL; }
void * signal_task_shutdown_thread(void* ignored) { if(!dnscore_shuttingdown()) { log_debug("signal_task_shutdown_thread: begin"); program_mode = SA_SHUTDOWN; dnscore_shutdown(); log_debug("signal_task_shutdown_thread: end"); } pthread_exit(NULL); return NULL; }
void * signal_task_database_save_all_zones_to_disk_thread(void* ignored) { if(!dnscore_shuttingdown()) { log_debug("signal_task_database_save_all_zones_to_disk_thread: begin"); database_save_all_zones_to_disk(); signal_task_database_save_all_zones_to_disk_active = FALSE; log_debug("signal_task_database_save_all_zones_to_disk_thread: end"); } pthread_exit(NULL); return NULL; }
ya_result zdb_icmtl_replay(zdb_zone *zone) { ya_result return_value; u32 serial; zdb_zone_double_lock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); return_value = zdb_zone_getserial(zone, &serial); // zone is locked if(FAIL(return_value)) { zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); log_err("journal: %{dnsname}: error reading serial for zone: %r", zone->origin, return_value); return return_value; } input_stream is; #if ICMTL_DUMP_JOURNAL_RECORDS log_debug("journal: zdb_icmtl_replay(%{dnsname})", zone->origin); logger_flush(); #endif u32 first_serial; u32 last_serial; if(FAIL(return_value = zdb_zone_journal_get_serial_range(zone, &first_serial, &last_serial))) { zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); if(return_value == ZDB_ERROR_ICMTL_NOTFOUND) { return_value = SUCCESS; } else { log_err("journal: %{dnsname}: error opening journal for zone: %r", zone->origin, return_value); } return return_value; } log_debug("journal: %{dnsname}: zone serial is %i, journal covers serials from %i to %i", zone->origin, serial, first_serial, last_serial); if(last_serial == serial) { zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); log_debug("journal: %{dnsname}: nothing to read from the journal", zone->origin); return 0; } if(serial_lt(serial, first_serial)) { zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); log_warn("journal: %{dnsname}: first serial from the journal is after the zone", zone->origin); // should invalidate the journal zdb_zone_journal_delete(zone); return 0; } if(serial_gt(serial, last_serial)) { zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); log_warn("journal: %{dnsname}: last serial from the journal is before the zone", zone->origin); // should invalidate the journal zdb_zone_journal_delete(zone); return 0; } if(FAIL(return_value = zdb_zone_journal_get_ixfr_stream_at_serial(zone, serial, &is, NULL))) { zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); log_err("journal: %{dnsname}: error reading journal from serial %d: %r",zone->origin, serial, return_value); return return_value; } log_info("journal: %{dnsname}: replaying from serial %u",zone->origin, serial); buffer_input_stream_init(&is, &is, ZDB_ICMTL_REPLAY_BUFFER_SIZE); u16 shutdown_test_countdown = ZDB_ICMTL_REPLAY_SHUTDOWN_POLL_PERIOD; u32 current_serial = serial; /* * Read all records from [ SOA ... SOA ... [ SOA in memory */ output_stream baos; input_stream bais; dns_resource_record rr; int baos_rr_count = 0; int baos_soa_count = 0; bool was_nsec3 = zdb_zone_is_nsec3(zone); bytearray_output_stream_init_ex(&baos, NULL, ZDB_ICMTL_REPLAY_BUFFER_SIZE, BYTEARRAY_DYNAMIC); dns_resource_record_init(&rr); // 0: gather, 1: commit, 2: commit & stop for(int replay_state = ZDB_ICMTL_REPLAY_GATHER; replay_state != ZDB_ICMTL_REPLAY_COMMIT_AND_STOP;) { // ensure it's not supposed to shutdown (every few iterations) if(--shutdown_test_countdown <= 0) { if(dnscore_shuttingdown()) { return_value = STOPPED_BY_APPLICATION_SHUTDOWN; break; } shutdown_test_countdown = ZDB_ICMTL_REPLAY_SHUTDOWN_POLL_PERIOD; } // read the next record if((return_value = dns_resource_record_read(&rr, &is)) <= 0) { if(ISOK(return_value)) { log_info("journal: %{dnsname}: reached the end of the journal file", zone->origin); replay_state = ZDB_ICMTL_REPLAY_COMMIT_AND_STOP; } else { log_err("journal: broken journal: %r", return_value); logger_flush(); // broken journal (flush is slow, but this is bad, so : keep it) replay_state = ZDB_ICMTL_REPLAY_STOP; } } else // first record must be an SOA (or it's wrong) if(baos_rr_count == 0) // first record ? { if(rr.tctr.qtype != TYPE_SOA) // must be SOA { // expected an SOA return_value = ERROR; break; } ++baos_soa_count; // 0 -> 1 // this is not mandatory but clearer to read } else // the page ends with an SOA or end of stream if(rr.tctr.qtype == TYPE_SOA) { if(baos_soa_count == 2) { // this record is the start of the next stream, keep it for the next iteration replay_state = ZDB_ICMTL_REPLAY_COMMIT; } ++baos_soa_count; } ++baos_rr_count; if((replay_state & ZDB_ICMTL_REPLAY_COMMIT) != 0) { log_info("journal: %{dnsname}: committing changes", zone->origin); u64 ts_start = timeus(); zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); bytearray_input_stream_init_const(&bais, bytearray_output_stream_buffer(&baos), bytearray_output_stream_size(&baos)); return_value = zdb_icmtl_replay_commit(zone, &bais, ¤t_serial); zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_LOAD, ZDB_ZONE_MUTEX_SIMPLEREADER); input_stream_close(&bais); u64 ts_stop = timeus(); if(ts_stop < ts_start) // time change { ts_stop = ts_start; } u64 ts_delta = ts_stop - ts_start; if(ISOK(return_value)) { if(ts_delta < 1000) { log_info("journal: %{dnsname}: committed changes (%lluus)", zone->origin, ts_delta); } else if(ts_delta < 1000000) { double ts_delta_s = ts_delta; ts_delta_s /= 1000.0; log_info("journal: %{dnsname}: committed changes (%5.2fms)", zone->origin, ts_delta_s); } else { double ts_delta_s = ts_delta; ts_delta_s /= 1000000.0; log_info("journal: %{dnsname}: committed changes (%5.2fs)", zone->origin, ts_delta_s); } } else { log_err("journal: %{dnsname}: failed to committed changes", zone->origin); break; } // the current page has been processed if(replay_state == ZDB_ICMTL_REPLAY_COMMIT_AND_STOP) { // no more page to read break; } // reset the state for the next page // note: the next written record will be the last read SOA baos_rr_count = 1; baos_soa_count = 1; replay_state = ZDB_ICMTL_REPLAY_GATHER; bytearray_output_stream_reset(&baos); } // end if replay_state is ZDB_ICMTL_REPLAY_COMMIT (mask) dns_resource_record_write(&rr, &baos); } input_stream_close(&is); output_stream_close(&baos); dns_resource_record_clear(&rr); // cleanup destroyed nsec3 chains if(ISOK(return_value)) { bool is_nsec3 = zdb_zone_is_nsec3(zone); if(is_nsec3 && !was_nsec3) { // the chain has just been created, but is probably missing internal links log_debug("journal: %{dnsname}: zone switched to NSEC3 by reading the journal: updating links", zone->origin); zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); nsec3_zone_update_chain0_links(zone); zdb_zone_exchange_locks(zone, ZDB_ZONE_MUTEX_LOAD, ZDB_ZONE_MUTEX_SIMPLEREADER); log_debug("journal: %{dnsname}: zone switched to NSEC3 by reading the journal: links updated", zone->origin); } if(FAIL(return_value = zdb_zone_getserial(zone, &serial))) // zone is locked { zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); log_err("journal: %{dnsname}: error reading confirmation serial for zone: %r",zone->origin, return_value); return return_value; } if(serial != last_serial) { log_warn("journal: %{dnsname}: expected serial to be %i but it is %i instead",zone->origin, last_serial, serial); } #if 0 // ICMTL_DUMP_JOURNAL_RECORDS if(is_nsec) { nsec_logdump_tree(zone); logger_flush(); } #endif } zdb_zone_double_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER, ZDB_ZONE_MUTEX_LOAD); log_info("journal: %{dnsname}: done", zone->origin); return return_value; }
ya_result zdb_zone_axfr_input_stream_open(input_stream *is, zdb_zone *zone) { ya_result ret; u32 serial; u32 timestamp; char path[PATH_MAX]; serial = zone->axfr_serial; timestamp = zone->axfr_timestamp; while(timestamp == 0) { /* * being written : try to open the axfr.part file * in the event of a success, a stream waiting for the completion of the file will be returned */ if(ISOK(ret = zdb_zone_path_get_provider()( zone->origin, path, sizeof(path) - 6, ZDB_ZONE_PATH_PROVIDER_AXFR_FILE|ZDB_ZONE_PATH_PROVIDER_MKDIR))) { memcpy(&path[ret], ".part", 6); if(ISOK(ret = file_input_stream_open(is, path))) { zdb_zone_axfr_input_stream_data* data; MALLOC_OR_DIE(zdb_zone_axfr_input_stream_data*, data, sizeof(zdb_zone_axfr_input_stream_data), AXFRIS_TAG); data->filtered.data = is->data; data->filtered.vtbl = is->vtbl; data->serial = serial; data->zone = zone; is->data = data; is->vtbl = &zdb_zone_axfr_input_stream_vtbl; return ret; } } if(dnscore_shuttingdown()) { return STOPPED_BY_APPLICATION_SHUTDOWN; } usleep(10000); serial = zone->axfr_serial; timestamp = zone->axfr_timestamp; } /* * already written : try to open the axfr file * in the event of a success, a simple file input stream will be returned */ if(ISOK(ret = zdb_zone_path_get_provider()( zone->origin, path, sizeof(path) - 6, ZDB_ZONE_PATH_PROVIDER_AXFR_FILE|ZDB_ZONE_PATH_PROVIDER_MKDIR))) { ret = file_input_stream_open(is, path); } return ret; }
ya_result scheduler_do_next_job() { /** @todo use the pool counters * _ Readers * _ Writers * _ Current Task : I can have a task that works bit by bit and continues until the last bit is done (RRSIG) */ /* Dequeue a job */ if(threaded_queue_size(&scheduler_queue) == 0) { return SCHEDULER_TASK_NOTHING; } scheduler_task *task = threaded_queue_dequeue(&scheduler_queue); /* Do (part) of the job */ scheduler_task_callback *callback = task->task; void* args = task->args; free(task); ya_result return_code; switch(return_code = callback(args)) { default: /* An error occurred */ log_err("scheduler: unexpected callback return code %r", return_code); case SCHEDULER_TASK_FINISHED: #ifndef NDEBUG log_debug("scheduler: task finished"); #endif /** * Retrieve and start the next thread * * @todo EXCEPT IF A SHUTDOWN HAS BEEN REQUESTED ? */ case SCHEDULER_TASK_DEQUEUE_DELAYED: if(dnscore_shuttingdown()) { log_info("scheduler: shutdown in progress : ignoring next job"); logger_flush(); return STOPPED_BY_APPLICATION_SHUTDOWN; } pthread_mutex_lock(&scheduler_delayed_queue_mutex); scheduler_thread_running = FALSE; if(!scheduler_thread_queue_isempty(&scheduler_delayed_queue)) { scheduler_thread* thread = scheduler_thread_queue_dequeue(&scheduler_delayed_queue); #ifndef NDEBUG log_debug("scheduler: dequeued thread %s::(%p, %p, %p, %p@%u)", thread->categoryname, thread->task_init, thread->task, thread->args, thread, thread->debug_count); log_debug("scheduler: starting thread %u", thread->debug_count); log_debug("scheduler: next thread init"); #endif if(thread->task_init != NULL) { thread->task_init(thread->args); } #ifndef NDEBUG log_debug("scheduler: next thread ready"); #endif if(thread->task != NULL) { #ifndef NDEBUG log_debug("scheduler: next thread start"); #endif scheduler_thread_running = TRUE; thread_pool_schedule_job(thread->task, thread->args, &scheduler_threads_counter, thread->categoryname); } free(thread); } pthread_mutex_unlock(&scheduler_delayed_queue_mutex); break; case SCHEDULER_TASK_PROGRESS: /* NOP */ #ifndef NDEBUG log_debug("scheduler: task progress"); #endif break; } return return_code; }