Exemplo n.º 1
0
/* write a blob to disk */
static void write_blob_to_disk(disk_writer_t *self, blob_t *b) {
    assert(BLOB_REF_PTR(b));
    
    setup_for_epoch(self, BLOB_RECEIVED_TIME(b).tv_sec);

    if ( self->fd >= 0 ) {
        ssize_t wrote= write(self->fd, BLOB_BUF(b), BLOB_BUF_SIZE(b));
        if ( wrote == BLOB_BUF_SIZE(b) ) {
            RELAY_ATOMIC_INCREMENT( self->pcounters->disk_count, 1 );
            return;
        }
        WARN_ERRNO("Wrote only %ld of %i bytes to '%s', error:",
                wrote, BLOB_BUF_SIZE(b), self->last_file_path);

    }
    RELAY_ATOMIC_INCREMENT( self->pcounters->disk_error_count, 1 );
}
Exemplo n.º 2
0
static int process_queue(socket_worker_t * self, relay_socket_t * sck, queue_t * private_queue, queue_t * spill_queue,
                         ssize_t * wrote)
{
    if (sck == NULL) {
        WARN("NULL forwarding socket");
        return 0;
    }

    blob_t *cur_blob;
    struct timeval now;
    struct timeval send_start_time;
    struct timeval send_end_time;
    stats_count_t spilled = 0;

    const config_t *config = self->base.config;
    const uint64_t spill_microsec = 1000 * config->spill_millisec;
    const uint64_t grace_microsec = 1000 * config->spill_grace_millisec;

    const struct sockaddr *dest_addr = (const struct sockaddr *) &sck->sa.in;
    socklen_t addr_len = sck->addrlen;

    int in_grace_period = 0;
    struct timeval grace_period_start;

    int failed = 0;

    *wrote = 0;

    get_time(&send_start_time);

    cork(sck, 1);

    while (private_queue->head != NULL) {
        get_time(&now);

        /* While not all the socket backends are present, for a configured maximum time,
         * do not spill/drop. This is a bit crude, better rules/heuristics welcome. */
        if (!connected_all()) {
            if (in_grace_period == 0) {
                in_grace_period = 1;
                get_time(&grace_period_start);
                SAY("Spill/drop grace period of %d millisec started", config->spill_grace_millisec);
            }
            if (elapsed_usec(&grace_period_start, &now) >= grace_microsec) {
                in_grace_period = 0;
                SAY("Spill/drop grace period of %d millisec expired", config->spill_grace_millisec);
            }
        } else {
            if (in_grace_period) {
                SAY("Spill/drop grace period of %d millisec canceled", config->spill_grace_millisec);
            }
            in_grace_period = 0;
        }

        if (in_grace_period == 0) {
            spilled += spill_by_age(self, config->spill_enabled, private_queue, spill_queue, spill_microsec, &now);
        }

        cur_blob = private_queue->head;
        if (!cur_blob)
            break;

        void *blob_data;
        ssize_t blob_size;

        if (sck->type == SOCK_DGRAM) {
            blob_size = BLOB_BUF_SIZE(cur_blob);
            blob_data = BLOB_BUF_addr(cur_blob);
        } else {                /* sck->type == SOCK_STREAM */
            blob_size = BLOB_DATA_MBR_SIZE(cur_blob);
            blob_data = BLOB_DATA_MBR_addr(cur_blob);
        }

        ssize_t blob_left = blob_size;
        ssize_t blob_sent = 0;
        int sendto_errno = 0;

        failed = 0;

        /* Keep sending while we have data left since a single sendto()
         * doesn't necessarily send all of it.  This may eventually fail
         * if sendto() returns -1. */
        while (!RELAY_ATOMIC_READ(self->base.stopping) && blob_left > 0) {
            const void *data = (const char *) blob_data + blob_sent;
            ssize_t sent;

            sendto_errno = 0;
            if (sck->type == SOCK_DGRAM) {
                sent = sendto(sck->socket, data, blob_left, MSG_NOSIGNAL, dest_addr, addr_len);
            } else {            /* sck->type == SOCK_STREAM */
                sent = sendto(sck->socket, data, blob_left, MSG_NOSIGNAL, NULL, 0);
            }
            sendto_errno = errno;

            if (0) {            /* For debugging. */
                peek_send(sck, data, blob_left, sent);
            }

            if (sent == -1) {
                WARN_ERRNO("sendto() tried sending %zd bytes to %s but sent none", blob_left, sck->to_string);
                RELAY_ATOMIC_INCREMENT(self->counters.error_count, 1);
                if (sendto_errno == EINTR) {
                    /* sendto() got interrupted by a signal.  Wait a while and retry. */
                    WARN("Interrupted, resuming");
                    worker_wait_millisec(config->sleep_after_disaster_millisec);
                    continue;
                }
                failed = 1;
                break;          /* stop sending from the hijacked queue */
            }

            blob_sent += sent;
            blob_left -= sent;
        }

        if (blob_sent == blob_size) {
            RELAY_ATOMIC_INCREMENT(self->counters.sent_count, 1);
        } else if (blob_sent < blob_size) {
            /* Despite the send-loop above, we failed to send all the bytes. */
            WARN("sendto() tried sending %zd bytes to %s but sent only %zd", blob_size, sck->to_string, blob_sent);
            RELAY_ATOMIC_INCREMENT(self->counters.partial_count, 1);
            failed = 1;
        }

        *wrote += blob_sent;

        if (failed) {
            /* We failed to send this packet.  Exit the loop, and
             * right after the loop close the socket, and get out,
             * letting the main loop to reconnect. */
            if ((sendto_errno == EAGAIN || sendto_errno == EWOULDBLOCK)) {
                /* Traffic jam.  Wait a while, but still get out. */
                WARN("Traffic jam");
                worker_wait_millisec(config->sleep_after_disaster_millisec);
            }
            break;
        } else {
            queue_shift_nolock(private_queue);
            blob_destroy(cur_blob);
        }
    }

    cork(sck, 0);

    get_time(&send_end_time);

    if (spilled) {
        if (config->spill_enabled) {
            WARN("Wrote %lu items which were over spill threshold", (unsigned long) spilled);
        } else {
            WARN("Spill disabled: DROPPED %lu items which were over spill threshold", (unsigned long) spilled);
        }
    }

    /* this assumes end_time >= start_time */
    uint64_t usec = elapsed_usec(&send_start_time, &send_end_time);
    RELAY_ATOMIC_INCREMENT(self->counters.send_elapsed_usec, usec);

    return failed == 0;
}