void copy_from_disk_queue_to_memory_queue(auto_drainer_t::lock_t keepalive) {
     try {
         while (!keepalive.get_drain_signal()->is_pulsed()) {
             if (disk_queue->empty()) {
                 if (items_in_queue != memory_queue.size()) {
                     // There is a push in progress, there's no good way to wait on it, so we'll start a new coroutine later
                     restart_copy_coro = true;
                 } else {
                     disk_queue.reset();
                 }
                 break;
             }
             T value;
             disk_queue->pop(&value);
             if (memory_queue.full()) {
                 guarantee(notify_when_room_in_memory_queue == NULL);
                 cond_t cond;
                 assignment_sentry_t<cond_t *> assignment_sentry(&notify_when_room_in_memory_queue, &cond);
                 wait_interruptible(&cond, keepalive.get_drain_signal());
             }
             memory_queue.push_back(value);
             available_control.set_available(true);
         }
     } catch (const interrupted_exc_t &) {
         /* ignore */
     }
 }
 void copy_from_disk_queue_to_memory_queue(auto_drainer_t::lock_t keepalive) {
     try {
         while (!keepalive.get_drain_signal()->is_pulsed()) {
             if (disk_queue->empty()) {
                 if (items_in_queue != memory_queue.size()) {
                     // There is a push in progress, there's no good way to wait on
                     // it, so we'll start a new coroutine later
                     restart_copy_coro = true;
                 } else {
                     disk_queue.reset();
                 }
                 break;
             }
             write_message_t wm;
             copying_viewer_t viewer(&wm);
             disk_queue->pop(&viewer);
             if (memory_queue_free_space <= 0) {
                 guarantee(notify_when_room_in_memory_queue == nullptr);
                 cond_t cond;
                 assignment_sentry_t<cond_t *> assignment_sentry(
                     &notify_when_room_in_memory_queue, &cond);
                 wait_interruptible(&cond, keepalive.get_drain_signal());
             }
             memory_queue_free_space -= wm.size();
             memory_queue.emplace_back(std::move(wm));
             available_control.set_available(true);
         }
     } catch (const interrupted_exc_t &) {
         /* ignore */
     }
 }
 void perform_request(const request_type &request, auto_drainer_t::lock_t keepalive) {
     requests_since_last_qps_sample++;
     try {
         registrant.perform_request(request, keepalive.get_drain_signal());
     } catch (interrupted_exc_t) {
         /* ignore */
     }
     in_use_tickets--;
     parent->return_tickets(1);
 }
Exemple #4
0
    void on_create(registration_id_t rid, peer_id_t peer, business_card_t business_card, auto_drainer_t::lock_t keepalive) {

        /* Grab the mutex to avoid race conditions if a message arrives at the
        update mailbox or the delete mailbox while we're working. We must not
        block between when `on_create()` begins and when `mutex_acq` is
        constructed. */
        mutex_t::acq_t mutex_acq(&mutex);

        /* If the registrant has already deregistered but the deregistration
        message arrived ahead of the registration message, it will have left a
        NULL in the `registrations` map. */
        typename std::map<registration_id_t, cond_t *>::iterator it = registrations.find(rid);
        if (it != registrations.end()) {
            guarantee(it->second == NULL);
            registrations.erase(it);
            return;
        }

        /* Construct a `registrant_t` to tell the controller that something has
        now registered. */
        registrant_type registrant(controller, business_card);

        /* `registration` is the interface that we expose to the `on_update()`
        and `on_delete()` handlers. */
        cond_t deletion_cond;

        /* Expose `deletion_cond` so that `on_delete()` can find it. */
        map_insertion_sentry_t<registration_id_t, cond_t *> registration_map_sentry(
            &registrations, rid, &deletion_cond);

        /* Begin monitoring the peer so we can disconnect when necessary. */
        disconnect_watcher_t peer_monitor(mailbox_manager->get_connectivity_service(), peer);

        /* Release the mutex, since we're done with our initial setup phase */
        {
            mutex_t::acq_t doomed;
            swap(mutex_acq, doomed);
        }

        /* Wait till it's time to shut down */
        wait_any_t waiter(&deletion_cond, &peer_monitor, keepalive.get_drain_signal());
        waiter.wait_lazily_unordered();

        /* Reacquire the mutex, to avoid race conditions when we're
        deregistering from `deleters`. I'm not sure if there re any such race
        conditions, but better safe than sorry. */
        {
            mutex_t::acq_t reacquisition(&mutex);
            swap(mutex_acq, reacquisition);
        }

        /* `registration_map_sentry` destructor run here; `deletion_cond` cannot
        be pulsed after this. */

        /* `deletion_cond` destructor run here. */

        /* `registrant` destructor run here; this will tell the controller that
        the registration is dead and gone. */

        /* `mutex_acq` destructor run here; it's safe to release the mutex
        because we're no longer touching `updaters` or `deleters`. */
    }