A project back end consists of a set of programs, some of which have project- or application-specific parts.

Component BOINC-supplied part project-supplied part
Work generator: generates work units and the corresponding input files. Interfaces for creating workunits. Programs or scripts that generate input files, install them on data servers, and call the BOINC interface functions.
Transitioner: Handles various state transitions of workunits and results, such as timeouts. Generates results for workunits as needed. A program transitioner. None
Result validation and accounting: compare redundant results; select a canonical result representing the correct output, and a canonical credit granted to users and hosts that return the correct output. A program, validate, that contains the basic logic for validation. An application-specific function, linked with validate, that compares sets of redundant results.
Assimilator: handles workunits that are 'completed': that is, that have a canonical result or for which an error condition has occurred. Handling a successfully completed result might involve record results in a database and perhaps generating more work. A program assimilator that contains the basic logic for assimilation. A handler function that assimilates a workunit, either by processing its canonical result or handling an error return.
File deleter: delete input and output files when they are no longer needed. A program file_deleter. None.

Work generator

    for each wu created
        wu.transition_time = now

scheduler

    when send a result
        result.report_deadline = now + wu.delay_bound
        wu.transition_time = min(wu.transition_time, result.report_deadline)
    when receive a result
        if client error
            result.outcome = client_error
            result.validate_state = INVALID
        else
            result.outcome = success
        result.server_state = OVER
        wu.transition_time = now
    when a result falls off the bottom of infeasible queue
        result.server_state = OVER
        result.outcome = COULDNT_SEND
        wu.transition_time = now

Transitioner

// gets run when either
// - a result becomes done (via timeout or client reply)
// - the WU error mask is set (e.g. by validater)
// - assimilation is finished
    for each WU with now > transition_time:

        // check for timed-out results
        for each result of WU
            if result.server_state = in_progress and now > result.report_deadline
                result.server_state = OVER
                result.outcome = NO_REPLY

        // trigger validation if needed
        K = # of SUCCESS results
        if K >= M
            if any result is server_state OVER, outcome SUCCESS, validate_state INIT
                wu.need_validate = true

        // check for WU error conditions
        if any result has outcome couldnt_send
            error_mask |= couldnt_send
        K = # results with outcome = client_error
        if K > A
            error_mask |= too_many_error_results

        // Note: check on # of success results is done in validator

        K = total # results
        if K > B
            error_mask |= too_many_total_results
        
        // if no WU errors, generate new results if needed
        if error_mask == 0
            K = # results w/ server_state = unsent or in_progress
            L = N - K
            generate L new results
        
        // if WU errors, clean up unsent results
        // and trigger assimilation if needed
        if error_mask
            for all results server_state = unsent
                server_state = over
                outcome = didnt_need
            if wu.assimilate_state == init
                wu.assimilate_state = ready
        
        // if WU is assimilated, trigger deletion of files
        if wu.assimilated_state = DONE
            // trigger input file deletion if needed
            if all results are OVER
                wu.file_delete_state = ready

                // we can delete the canonical result output files
                // if all successful results have been validated
                if have canonical result and canonical_result.file_delete_state == INIT:
                    if all results are != SUCCESS or (VALID or INVALID):
                        canonical_result.file_delete_state = READY

            // outputs of error results can be deleted immediately;
            // outputs of successful results can be deleted when validated
            for results outcome = CLIENT_ERROR or (SUCCESS and (VALID or INVALID))
                if file_delete_state = INIT
                    result.file_delete_state = READY

        // get next result timeout if any
        transition_time = MAX_INT
        if any results are IN_PROGRESS
            transition_time = min(result.report_deadline)

Validator

BOINC supplies a utility program validate to perform validation and credit-granting. This program must be linked with two project-specific functions:

int check_set(vector results, int& canonicalid, double& credit);
int check_pair(RESULT& r1, RESULT& r2, bool& match);
check_set() takes a set of results. If there is sufficient agreement, it selects one of them as the canonical result (returning its ID) and also decides what credit should be granted for correct results for this workunit.

check_pair() compares two results and returns match=true if they agree.

The file validate_test.C contains an example implementation of check_set() and check_pair().

    for each WU w/ need_validate true
        if have canonical result
            for each result w/ validate_state INIT and outcome SUCCESS
                // possible that we've already deleted canonical output files
                if canonical_result.file_delete_state = DONE
                    validate_state = INVALID
                else
                    if matches canonical, grant credit
                    validate_state = VALID or INVALID
                need_to_handle_over_results = true
        else
            S = set of results w/ outcome SUCCESS
            if consensus(S)
                set canonical_result
                set success results as VALID or INVALID
                grant credit
                need_to_handle_over_results = true
                wu.assimilate_state = READY
                for all results server_state UNSENT
                    server_state = OVER
                    outcome = DIDNT_NEED
            else
                if # of successful results > C
                    wu.error_mask |= too_many_success_result
                    need_to_handle_over_results = true

        if need_to_handle_over_results:
            wu.transition_time = now

Assimilator

    for each WU with assimilate_state = READY
        call project-specific handler function
        wu.assimilate_state = done
        wu.transition_time = now
"; page_tail(); ?>