Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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, &current_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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}