Beispiel #1
0
ngx_int_t websocket_subscriber_destroy(subscriber_t *sub) {
  full_subscriber_t   *fsub = (full_subscriber_t  *)sub;
  nchan_request_ctx_t *ctx;
  if(!fsub->awaiting_destruction) {
    ctx = ngx_http_get_module_ctx(fsub->sub.request, nchan_module);
    ctx->sub = NULL;
  }
  
  if(fsub->upstream_stuff && fsub->upstream_stuff->psr_data.tmp_pool) {
    ngx_destroy_pool(fsub->upstream_stuff->psr_data.tmp_pool);
  }
   
  if(sub->reserved > 0) {
    DBG("%p not ready to destroy (reserved for %i) for req %p", sub, sub->reserved, fsub->sub.request);
    fsub->awaiting_destruction = 1;
  }
  else {
    DBG("%p destroy for req %p", sub, fsub->sub.request);
    nchan_free_msg_id(&fsub->sub.last_msgid);
#if NCHAN_SUBSCRIBER_LEAK_DEBUG
    subscriber_debug_remove(&fsub->sub);
#endif
    nchan_free_msg_id(&sub->last_msgid);
    //debug 
    ngx_memset(fsub, 0x13, sizeof(*fsub));
    ngx_free(fsub);
  }
  return NGX_OK;
}
Beispiel #2
0
ngx_int_t stop_spooler(channel_spooler_t *spl, uint8_t dequeue_subscribers) {
  ngx_rbtree_node_t    *cur, *sentinel;
  spooler_event_ll_t   *ecur, *ecur_next;
  subscriber_pool_t    *spool;
  rbtree_seed_t        *seed = &spl->spoolseed;
  ngx_rbtree_t         *tree = &seed->tree;
  ngx_int_t             n=0;
  sentinel = tree->sentinel;
  
  fetchmsg_data_t      *dcur;
#if NCHAN_RBTREE_DBG
  ngx_int_t active_before = seed->active_nodes, allocd_before = seed->active_nodes;
#endif
  if(spl->running) {
    
    for(ecur = spl->spooler_dependent_events; ecur != NULL; ecur = ecur_next) {
      ecur_next = ecur->next;
      if(ecur->cancel) {
        ecur->cancel(ecur->ev.data);
      }
      ngx_event_del_timer(&ecur->ev);
      
      ngx_free(ecur);
    }
    
    for(cur = tree->root; cur != NULL && cur != sentinel; cur = tree->root) {
      spool = (subscriber_pool_t *)rbtree_data_from_node(cur);
      if(dequeue_subscribers) {
        destroy_spool(spool);
      }
      else {
        remove_spool(spool);
        rbtree_destroy_node(seed, cur);
      }
      n++;
    }
    
    for(dcur = spl->fetchmsg_cb_data_list; dcur != NULL; dcur = dcur->next) {
      dcur->spooler = NULL;
    }
    
    DBG("stopped %i spools in SPOOLER %p", n, *spl);
  }
  else {
    DBG("SPOOLER %p not running", *spl);
  }
#if NCHAN_RBTREE_DBG
  assert(active_before - n == 0);
  assert(allocd_before - n == 0);
  assert(seed->active_nodes == 0);
  assert(seed->allocd_nodes == 0);
#endif
  nchan_free_msg_id(&spl->prev_msg_id);
  spl->running = 0;
  return NGX_OK;
}
Beispiel #3
0
ngx_int_t msg_release(nchan_msg_t *msg, char *lbl) {
  nchan_msg_t    *parent = msg->parent;
  if(parent) {
    assert(msg->storage != NCHAN_MSG_SHARED);
#if NCHAN_MSG_RESERVE_DEBUG
    nchan_msg_release_debug(msg, lbl);
#endif
    msg->refcount--;
    assert(msg->refcount >= 0);
    
    if(msg->refcount == 0) {
      switch(msg->storage) {
        case NCHAN_MSG_POOL:
          //free the id, the rest of the msg will be cleaned with the pool
          nchan_free_msg_id(&msg->id);
          break;
          
        case NCHAN_MSG_HEAP:
          nchan_free_msg_id(&msg->id);
          ngx_free(msg);
          break;
          
        default:
          break;
          //do nothing for NCHAN_MSG_STACK. NCHAN_MSG_SHARED should never be seen here.
      }
    }
    return msg_release(parent, lbl);
  }
  assert(!parent);
  
#if NCHAN_MSG_RESERVE_DEBUG
  nchan_msg_release_debug(msg, lbl);
#endif
  assert(msg->refcount > 0);
  ngx_atomic_fetch_add((ngx_atomic_uint_t *)&msg->refcount, -1);
  //DBG("msg %p released (%i) %s", msg, msg->refcount, lbl);
  return NGX_OK;
}
Beispiel #4
0
static ngx_int_t remove_spool(subscriber_pool_t *spool) {
  channel_spooler_t    *spl = spool->spooler;
  ngx_rbtree_node_t    *node = rbtree_node_from_data(spool);
  
  DBG("remove spool node %p", node);
  
  assert(spool->spooler->running);
  nchan_free_msg_id(&spool->id);
  rbtree_remove_node(&spl->spoolseed, rbtree_node_from_data(spool));

  //assert((node = rbtree_find_node(&spl->spoolseed, &spool->id)) == NULL);
  //double-check that it's gone 
  
  return NGX_OK;
}
Beispiel #5
0
ngx_int_t longpoll_subscriber_destroy(subscriber_t *sub) {
  full_subscriber_t   *fsub = (full_subscriber_t  *)sub;
  
  if(sub->reserved > 0) {
    DBG("%p not ready to destroy (reserved for %i) for req %p", sub, sub->reserved, fsub->sub.request);
    fsub->data.awaiting_destruction = 1;
  }
  else {
    DBG("%p destroy for req %p", sub, fsub->sub.request);
    nchan_free_msg_id(&fsub->sub.last_msgid);
#if NCHAN_SUBSCRIBER_LEAK_DEBUG
    subscriber_debug_remove(sub);
    ngx_free(sub->lbl);
    ngx_memset(fsub, 0xB9, sizeof(*fsub)); //debug
#endif
    ngx_free(fsub);
  }
  return NGX_OK;
}
Beispiel #6
0
static ngx_int_t spool_fetch_msg_callback(nchan_msg_status_t findmsg_status, nchan_msg_t *msg, fetchmsg_data_t *data) {
  nchan_msg_status_t    prev_status;
  subscriber_pool_t    *spool, *nuspool;
  channel_spooler_t    *spl = data->spooler;
  int                   free_msg_id = 1;
  
  if(spl && data == spl->fetchmsg_cb_data_list) {
    spl->fetchmsg_cb_data_list = data->next;
  }
  if(data->next) {
    data->next->prev = data->prev;
  }
  if(data->prev) {
    data->prev->next = data->next;
  }
  
  if(spl == NULL) { //channel already deleted
    nchan_free_msg_id(&data->msgid);
    ngx_free(data);
    return NGX_OK;
  }
  
  if(spl->handlers->get_message_finish) {
    spl->handlers->get_message_finish(spl, spl->handlers_privdata);
  }
  
  if((spool = find_spool(spl, &data->msgid)) == NULL) {
    DBG("spool for msgid %V not found. discarding getmsg callback response.", msgid_to_str(&data->msgid));
    nchan_free_msg_id(&data->msgid);
    ngx_free(data);
    return NGX_ERROR;
  }
  
  prev_status = spool->msg_status;
  
  switch(findmsg_status) {
    case MSG_FOUND:
      spool->msg_status = findmsg_status;
      DBG("fetchmsg callback for spool %p msg FOUND %p %V", spool, msg, msgid_to_str(&msg->id));
      assert(msg != NULL);
      spool->msg = msg;
      spool_respond_general(spool, spool->msg, 0, NULL, 0);
      
      spool_nextmsg(spool, &msg->id);      
      break;
    
    case MSG_EXPECTED:
      // ♫ It's gonna be the future soon ♫
      if(spool->id.time == NCHAN_NTH_MSGID_TIME) {
        //wait for message in the NEWEST_ID spool
        nchan_msg_id_t  newest_id = NCHAN_NEWEST_MSGID;
        spool_nextmsg(spool, &newest_id); 
      }
      else {
        spool->msg_status = findmsg_status;
        DBG("fetchmsg callback for spool %p msg EXPECTED", spool);
        spool_respond_general(spool, NULL, NGX_HTTP_NO_CONTENT, NULL, 0);
        assert(msg == NULL);
        spool->msg = NULL;
      }
      break;
      
    case MSG_NORESPONSE:
      if(prev_status == MSG_PENDING) {
        spool->msg_status = MSG_INVALID;
        if(spool->sub_count > 0) {
          nomsg_retry_data_t *retry_data = ngx_alloc(sizeof(*retry_data), ngx_cycle->log);
          
          retry_data->spooler = spl;
          
          free_msg_id = 0;
          retry_data->msg_id = data->msgid;
          
          spooler_add_timer(spl, NCHAN_MSG_NORESPONSE_RETRY_TIME, spool_fetch_msg_noresponse_retry_callback, spool_fetch_msg_noresponse_retry_cancel, retry_data);
        }
      }
      break;
      
    case MSG_NOTFOUND:
      if(spl->fetching_strategy == FETCH_IGNORE_MSG_NOTFOUND) {
        spool->msg_status = prev_status;
        break;
      }
    case MSG_EXPIRED:
      //is this right?
      //TODO: maybe message-expired notification
      spool->msg_status = findmsg_status;
      spool_respond_general(spool, NULL, NGX_HTTP_NO_CONTENT, NULL, 0);
      nuspool = get_spool(spool->spooler, &oldest_msg_id);
      if(spool != nuspool) {
        spool_transfer_subscribers(spool, nuspool, 1);
        destroy_spool(spool);
      }
      else {
        ERR("Unexpected spool == nuspool during spool fetch_msg_callback. This is weird, please report this to the developers. findmsg_status: %i", findmsg_status);
        assert(0);
      }
      break;
    
    case MSG_PENDING:
      ERR("spool %p set status to MSG_PENDING", spool);
      break;
      
    default:
      assert(0);
      break;
  }
  
  if(free_msg_id) {
    nchan_free_msg_id(&data->msgid);
  }
  ngx_free(data);
  return NGX_OK;
}
Beispiel #7
0
static void spool_fetch_msg_noresponse_retry_cancel(void *pd) {
  nomsg_retry_data_t *d = pd;
  nchan_free_msg_id(&d->msg_id);
  ngx_free(d);
}