Esempio n. 1
0
static ya_result
xfr_query_callback(void* data)
{
    xfr_query_schedule_param *xqsp = (xfr_query_schedule_param*)data;
    ya_result return_value;
	ya_result scheduler_status;
    u32 refreshed_time = 0;
    u32 retried_time = time(NULL);
    
    /*
     * Zone refresh will be enabled (again) here.
     * 
     * xfr_query_mark_zone_loaded
     * 
     */

    
    if(ISOK(xqsp->return_value))
    {
        /* success but type == 0 => transfer done */
        
        if(xqsp->type != 0)
        {
            log_info("slave: %{dnstype}: proceeding with transfer of %{dnsname}", &xqsp->type, xqsp->origin);
        }
    }
    else
    {
        log_err("slave: %{dnstype}: transfer of %{dnsname} failed: %r", &xqsp->type, xqsp->origin, xqsp->return_value);
        
        /*
         * Here (?) put the invalid zone placeholder if it is not there yet
         */
    }

    switch(xqsp->type)
    {
        case TYPE_AXFR:
        {
            /*
             * Load the axfr
             */
            
            if(ISOK(xqsp->return_value))
            {
                axfr_query_axfr_load_param *aqalp;
                MALLOC_OR_DIE(axfr_query_axfr_load_param*, aqalp, sizeof(axfr_query_axfr_load_param), GENERIC_TAG);
                
                log_info("slave: opening AXFR for %{dnsname} %d", xqsp->origin, xqsp->loaded_serial);

                if(ISOK(return_value = zone_axfr_reader_open_with_serial(g_config->xfr_path, xqsp->origin, xqsp->loaded_serial, &aqalp->zr)))
                {
                    /*
                     * The system is ready to load an AXFR
                     * A zone is already in place (by design), there may be an old zone that is now irrelevant.
                     * At this point ...
                     * 
                     * If the serial are not the same
                     *      MT the old zone must be destroyed (if it exist)
                     *       then
                     *      MT The new zone has to be created (loaded from the AXFR file)
                     * Else
                     *      ST The new zone is actually the old zone, and the old zone is non-existent
                     * EndIf
                     * 
                     * then
                     * 
                     * ST The new zone and the placeholder zone have to be swapped, then the placeholder has to be destroyed
                     * 
                     */
                    
                    zdb_zone *zone = zdb_zone_find_from_dnsname((zdb*)xqsp->db, xqsp->origin, CLASS_IN);

                    if(zone != NULL)
                    {
                        zdb_zone_truncate_invalidate(zone);
                    }                    

                    /**
                     * schedule the axfr load
                     */

                    aqalp->old_zone = NULL; /* old zone */
                    aqalp->new_zone = NULL;
                    aqalp->db = xqsp->db;
                    aqalp->origin = dnsname_dup(xqsp->origin);

                    scheduler_status = SCHEDULER_TASK_PROGRESS;

                    thread_pool_schedule_job(xfr_query_axfr_load_thread, aqalp, NULL, "axfr load");
                    
                    break;
                }
            }
            
            /**
             * @todo If the "old_zone" exists, then ... (destroy ? swap back ? expired ?)
             * 
             */
            
            /*
             * An issue occurred (AXFR transfer, load)
             */
			
            log_err("slave: unable to load the axfr (retry set in %d seconds)", g_config->axfr_retry_delay);

            alarm_event_node *event = alarm_event_alloc();

            event->epoch = time(NULL) + g_config->axfr_retry_delay;

            if(g_config->axfr_retry_jitter > 0)
            {
                random_ctx rndctx = thread_pool_get_random_ctx();
                u32 jitter = random_next(rndctx) % g_config->axfr_retry_jitter;
                event->epoch += jitter;
            }

            event->function = scheduler_axfr_query_alarm;
            event->args = xqsp;
            event->key = ALARM_KEY_ZONE_AXFR_QUERY;
            event->flags = ALARM_DUP_NOP;
            event->text = "scheduler_axfr_query_alarm";

            zdb *db = (zdb*)xqsp->db;
            alarm_set(db->alarm_handle, event);

            /* DO NOT FREE xqsp, SO DO NOT BREAK : return now */
            
            return SCHEDULER_TASK_FINISHED;
        }
        
        case TYPE_IXFR:
        {
            /**
             * Load the ixfr (single thread, zone locked)
             */

			scheduler_status = SCHEDULER_TASK_FINISHED;

            if(ISOK(xqsp->return_value))
            {
                zdb_zone *dbzone = zdb_zone_find_from_dnsname((zdb*)xqsp->db, xqsp->origin, CLASS_IN);

                if(dbzone == NULL)
                {
                    log_err("slave: zone %{dnsname} journal has vanished", xqsp->origin);
                    break;
                }
                
                log_info("slave: opening journal for '%{dnsname}'", xqsp->origin);

                zdb_zone_lock(dbzone, ZDB_ZONE_MUTEX_XFR);
                
                if(ISOK(return_value = zdb_icmtl_replay(dbzone, g_config->xfr_path, xqsp->serial_start_offset, xqsp->loaded_serial, ZDB_ICMTL_REPLAY_SERIAL_OFFSET|ZDB_ICMTL_REPLAY_SERIAL_LIMIT)))
                {
                    log_info("slave: replayed %d records changes", return_value);
                    
                    dbzone->apex->flags &= ~ZDB_RR_LABEL_INVALID_ZONE;
                    
                    refreshed_time = time(NULL);
                }
                else
                {
                    log_err("slave: replay error: %r this is bad: invalidate the zone and ask for an AXFR", return_value);
                    
                    /** @todo INVALIDATE AND AXFR */
                }
                
                /** @todo invalitate if retried_time > expired_time */

                zdb_zone_unlock(dbzone, ZDB_ZONE_MUTEX_XFR);
            }
            
            log_info("slave: journal transfer done");

            xfr_query_mark_zone_loaded((zdb*)g_config->database, xqsp->origin, refreshed_time, retried_time);
            
			scheduler_status = SCHEDULER_TASK_FINISHED;
            break;            
        }
        default:
        {
            refreshed_time = time(NULL);
            
            log_info("slave: transfer done");

            xfr_query_mark_zone_loaded((zdb*)g_config->database, xqsp->origin, refreshed_time, retried_time);
            
			scheduler_status = SCHEDULER_TASK_FINISHED;
            break;
        }
    }   /* switch return_value */
Esempio n. 2
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;
}