Exemplo n.º 1
0
// This function takes an array of arrays, each of which is of the
// form array($dbh, ...).  The only thing that matters in the inner
// arrays is the first element being a MySQL instance.  It then
// procedes to block for up to 'timeout' seconds, waiting for the
// first actionable descriptor(s), which it then returns in the form
// of the original arrays passed in.  The intention is the caller
// would include other information they care about in the tail of the
// array so they can decide how to act on the
// potentially-now-queryable descriptors.
//
// This function is a poor shadow of how the async library can be
// used; for more complex cases, we'd use libevent and share our event
// loop with other IO operations such as memcache ops, thrift calls,
// etc.  That said, this function is reasonably efficient for most use
// cases.
Variant f_mysql_async_wait_actionable(CVarRef items, double timeout) {
  size_t count = items.toArray().size();
  if (count == 0 || timeout < 0) {
    return Array::Create();
  }

  struct pollfd* fds = (struct pollfd*)calloc(count, sizeof(struct pollfd));
  SCOPE_EXIT { free(fds); };

  // Walk our input, determine what kind of poll() operation is
  // necessary for the descriptor in question, and put an entry into
  // fds.
  int nfds = 0;
  for (ArrayIter iter(items.toArray()); iter; ++iter) {
    Array entry = iter.second().toArray();
    if (entry.size() < 1) {
      raise_warning("element %d did not have at least one entry",
                   nfds);
      return Array::Create();
    }

    MySQL* mySQL = entry.rvalAt(0).toResource().getTyped<MySQL>();
    MYSQL* conn = mySQL->get();
    if (conn->async_op_status == ASYNC_OP_UNSET) {
      raise_warning("runtime/ext_mysql: no pending async operation in "
                    "progress");
      return Array::Create();
    }

    pollfd* fd = &fds[nfds++];
    fd->fd = mysql_get_file_descriptor(conn);
    if (conn->net.async_blocking_state == NET_NONBLOCKING_READ) {
      fd->events = POLLIN;
    } else {
      fd->events = POLLOUT;
    }
    fd->revents = 0;
  }

  // The poll itself; either the timeout is hit or one or more of the
  // input fd's is ready.
  int timeout_millis = static_cast<long>(timeout * 1000);
  int res = poll(fds, nfds, timeout_millis);
  if (res == -1) {
    raise_warning("unable to poll [%d]: %s", errno,
                  folly::errnoStr(errno).c_str());
    return Array::Create();
  }

  // Now just find the ones that are ready, and copy the corresponding
  // arrays from our input array into our return value.
  Array ret = Array::Create();
  nfds = 0;
  for (ArrayIter iter(items.toArray()); iter; ++iter) {
    Array entry = iter.second().toArray();
    if (entry.size() < 1) {
      raise_warning("element %d did not have at least one entry",
                   nfds);
      return Array::Create();
    }
    MySQL* mySQL = entry.rvalAt(0).toResource().getTyped<MySQL>();
    MYSQL* conn = mySQL->get();

    pollfd* fd = &fds[nfds++];
    if (fd->fd != mysql_get_file_descriptor(conn)) {
      raise_warning("poll returned events out of order wtf");
      continue;
    }
    if (fd->revents != 0) {
      ret.append(iter.second());
    }
  }

  return ret;
}
Exemplo n.º 2
0
static PyObject *
wsql_connection_get_file_descriptor(wsql_connection *self, void* closure)
{
    CHECK_CONNECTION(self, NULL);
    return PyLong_FromLong(mysql_get_file_descriptor(&(self->connection)));
}