コード例 #1
0
ファイル: thread.c プロジェクト: caizhifu/gearman
static void *_proc(void *data)
{
  gearman_server_st *server= (gearman_server_st *)data;
  gearman_server_thread_st *thread;
  gearman_server_con_st *con;
  gearman_server_packet_st *packet;

  while (1)
  {
    (void) pthread_mutex_lock(&(server->proc_lock));
    while (server->proc_wakeup == false)
    {
      if (server->proc_shutdown)
      {
        (void) pthread_mutex_unlock(&(server->proc_lock));
        return NULL;
      }

      (void) pthread_cond_wait(&(server->proc_cond), &(server->proc_lock));
    }
    server->proc_wakeup= false;
    (void) pthread_mutex_unlock(&(server->proc_lock));

    for (thread= server->thread_list; thread != NULL; thread= thread->next)
    {
      while ((con= gearman_server_con_proc_next(thread)) != NULL)
      {
        if (con->is_dead)
        {
          gearman_server_con_free_workers(con);

          while (con->client_list != NULL)
            gearman_server_client_free(con->client_list);

          con->proc_removed= true;
          gearman_server_con_io_add(con);
          continue;
        }

        while (1)
        {
          packet= gearman_server_proc_packet_remove(con);
          if (packet == NULL)
            break;

          con->ret= gearman_server_run_command(con, &(packet->packet));
          gearman_packet_free(&(packet->packet));
          gearman_server_packet_free(packet, con->thread, false);
        }
      }
    }
  }
}
コード例 #2
0
ファイル: server.c プロジェクト: Xobicvap/gearman-server
gearman_return_t gearman_server_run_command(gearman_server_con_st *server_con,
                                            gearman_packet_st *packet)
{
  gearman_return_t ret;
  gearman_server_job_st *server_job;
  char job_handle[GEARMAN_JOB_HANDLE_SIZE];
  char option[GEARMAN_OPTION_SIZE];
  gearman_server_client_st *server_client;
  char numerator_buffer[11]; /* Max string size to hold a uint32_t. */
  char denominator_buffer[11]; /* Max string size to hold a uint32_t. */
  gearman_job_priority_t priority;
  gearman_st *gearman= gearman= server_con->thread->server->gearman;

  if (packet->magic == GEARMAN_MAGIC_RESPONSE)
  {
    return _server_error_packet(server_con, "bad_magic",
                                "Request magic expected");
  }

  switch (packet->command)
  {
  /* Client/worker requests. */
  case GEARMAN_COMMAND_ECHO_REQ:
    /* Reuse the data buffer and just shove the data back. */
    ret= gearman_server_io_packet_add(server_con, true, GEARMAN_MAGIC_RESPONSE,
                                      GEARMAN_COMMAND_ECHO_RES, packet->data,
                                      packet->data_size, NULL);
    if (ret != GEARMAN_SUCCESS)
      return ret;

    packet->options&= (gearman_packet_options_t)~GEARMAN_PACKET_FREE_DATA;

    break;

  /* Client requests. */
  case GEARMAN_COMMAND_SUBMIT_JOB:
  case GEARMAN_COMMAND_SUBMIT_JOB_BG:
  case GEARMAN_COMMAND_SUBMIT_JOB_HIGH:
  case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG:
  case GEARMAN_COMMAND_SUBMIT_JOB_LOW:
  case GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG:

    if (packet->command == GEARMAN_COMMAND_SUBMIT_JOB ||
        packet->command == GEARMAN_COMMAND_SUBMIT_JOB_BG)
    {
      priority= GEARMAN_JOB_PRIORITY_NORMAL;
    }
    else if (packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH ||
             packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG)
    {
      priority= GEARMAN_JOB_PRIORITY_HIGH;
    }
    else
      priority= GEARMAN_JOB_PRIORITY_LOW;

    if (packet->command == GEARMAN_COMMAND_SUBMIT_JOB_BG ||
        packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG ||
        packet->command == GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG)
    {
      server_client= NULL;
    }
    else
    {
      server_client= gearman_server_client_add(server_con);
      if (server_client == NULL)
        return GEARMAN_MEMORY_ALLOCATION_FAILURE;
    }

    /* Create a job. */
    server_job= gearman_server_job_add(server_con->thread->server,
                                       (char *)(packet->arg[0]),
                                       packet->arg_size[0] - 1,
                                       (char *)(packet->arg[1]),
                                       packet->arg_size[1] - 1, packet->data,
                                       packet->data_size, priority,
                                       server_client, &ret);
    if (ret == GEARMAN_SUCCESS)
      packet->options&= (gearman_packet_options_t)~GEARMAN_PACKET_FREE_DATA;
    else if (ret == GEARMAN_JOB_QUEUE_FULL)
    {
      return _server_error_packet(server_con, "queue_full",
                                  "Job queue is full");
    }
    else if (ret != GEARMAN_JOB_EXISTS)
      return ret;

    /* Queue the job created packet. */
    ret= gearman_server_io_packet_add(server_con, false, GEARMAN_MAGIC_RESPONSE,
                                      GEARMAN_COMMAND_JOB_CREATED,
                                      server_job->job_handle,
                                      (size_t)strlen(server_job->job_handle),
                                      NULL);
    if (ret != GEARMAN_SUCCESS)
      return ret;

    break;

  case GEARMAN_COMMAND_GET_STATUS:
    /* This may not be NULL terminated, so copy to make sure it is. */
    snprintf(job_handle, GEARMAN_JOB_HANDLE_SIZE, "%.*s",
             (uint32_t)(packet->arg_size[0]), (char *)(packet->arg[0]));

    server_job= gearman_server_job_get(server_con->thread->server, job_handle);

    /* Queue status result packet. */
    if (server_job == NULL)
    {
      ret= gearman_server_io_packet_add(server_con, false,
                                        GEARMAN_MAGIC_RESPONSE,
                                        GEARMAN_COMMAND_STATUS_RES, job_handle,
                                        (size_t)(strlen(job_handle) + 1),
                                        "0", (size_t)2, "0", (size_t)2, "0",
                                        (size_t)2, "0", (size_t)1, NULL);
    }
    else
    {
      snprintf(numerator_buffer, 11, "%u", server_job->numerator);
      snprintf(denominator_buffer, 11, "%u", server_job->denominator);

      ret= gearman_server_io_packet_add(server_con, false,
                                        GEARMAN_MAGIC_RESPONSE,
                                        GEARMAN_COMMAND_STATUS_RES, job_handle,
                                        (size_t)(strlen(job_handle) + 1),
                                        "1", (size_t)2,
                                        server_job->worker == NULL ? "0" : "1",
                                        (size_t)2, numerator_buffer,
                                        (size_t)(strlen(numerator_buffer) + 1),
                                        denominator_buffer,
                                        (size_t)strlen(denominator_buffer),
                                        NULL);
    }

    if (ret != GEARMAN_SUCCESS)
      return ret;

    break;

  case GEARMAN_COMMAND_OPTION_REQ:
    /* This may not be NULL terminated, so copy to make sure it is. */
    snprintf(option, GEARMAN_OPTION_SIZE, "%.*s",
             (uint32_t)(packet->arg_size[0]), (char *)(packet->arg[0]));
    if (!strcasecmp(option, "exceptions"))
      server_con->options|= GEARMAN_SERVER_CON_EXCEPTIONS;
    else
    {
      return _server_error_packet(server_con, "unknown_option",
                                  "Server does not recognize given option");
    }

    ret= gearman_server_io_packet_add(server_con, false, GEARMAN_MAGIC_RESPONSE,
                                      GEARMAN_COMMAND_OPTION_RES,
                                      packet->arg[0], packet->arg_size[0],
                                      NULL);
    if (ret != GEARMAN_SUCCESS)
      return ret;

    break;

  /* Worker requests. */
  case GEARMAN_COMMAND_CAN_DO:
    if (gearman_server_worker_add(server_con, (char *)(packet->arg[0]),
                                  packet->arg_size[0], 0) == NULL)
    {
      return GEARMAN_MEMORY_ALLOCATION_FAILURE;
    }

    break;

  case GEARMAN_COMMAND_CAN_DO_TIMEOUT:
    if (gearman_server_worker_add(server_con, (char *)(packet->arg[0]),
                                  packet->arg_size[0] - 1,
                                  (in_port_t)atoi((char *)(packet->arg[1])))
         == NULL)
    {
      return GEARMAN_MEMORY_ALLOCATION_FAILURE;
    }

    break;

  case GEARMAN_COMMAND_CANT_DO:
    gearman_server_con_free_worker(server_con, (char *)(packet->arg[0]),
                                   packet->arg_size[0]);
    break;

  case GEARMAN_COMMAND_RESET_ABILITIES:
    gearman_server_con_free_workers(server_con);
    break;

  case GEARMAN_COMMAND_PRE_SLEEP:
    server_job= gearman_server_job_peek(server_con);
    if (server_job == NULL)
      server_con->options|= GEARMAN_SERVER_CON_SLEEPING;
    else
    {
      /* If there are jobs that could be run, queue a NOOP packet to wake the
         worker up. This could be the result of a race codition. */
      ret= gearman_server_io_packet_add(server_con, false,
                                        GEARMAN_MAGIC_RESPONSE,
                                        GEARMAN_COMMAND_NOOP, NULL);
      if (ret != GEARMAN_SUCCESS)
        return ret;
    }

    break;

  case GEARMAN_COMMAND_GRAB_JOB:
  case GEARMAN_COMMAND_GRAB_JOB_UNIQ:
    server_con->options&=
                     (gearman_server_con_options_t)~GEARMAN_SERVER_CON_SLEEPING;

    server_job= gearman_server_job_take(server_con);
    if (server_job == NULL)
    {
      /* No jobs found, queue no job packet. */
      ret= gearman_server_io_packet_add(server_con, false,
                                        GEARMAN_MAGIC_RESPONSE,
                                        GEARMAN_COMMAND_NO_JOB, NULL);
    }
    else if (packet->command == GEARMAN_COMMAND_GRAB_JOB_UNIQ)
    {
      /* We found a runnable job, queue job assigned packet and take the job
         off the queue. */
      ret= gearman_server_io_packet_add(server_con, false,
                                   GEARMAN_MAGIC_RESPONSE,
                                   GEARMAN_COMMAND_JOB_ASSIGN_UNIQ,
                                   server_job->job_handle,
                                   (size_t)(strlen(server_job->job_handle) + 1),
                                   server_job->function->function_name,
                                   server_job->function->function_name_size + 1,
                                   server_job->unique,
                                   (size_t)(strlen(server_job->unique) + 1),
                                   server_job->data, server_job->data_size,
                                   NULL);
    }
    else
    {
      /* Same, but without unique ID. */
      ret= gearman_server_io_packet_add(server_con, false,
                                   GEARMAN_MAGIC_RESPONSE,
                                   GEARMAN_COMMAND_JOB_ASSIGN,
                                   server_job->job_handle,
                                   (size_t)(strlen(server_job->job_handle) + 1),
                                   server_job->function->function_name,
                                   server_job->function->function_name_size + 1,
                                   server_job->data, server_job->data_size,
                                   NULL);
    }

    if (ret != GEARMAN_SUCCESS)
    {
      if (server_job != NULL)
        return gearman_server_job_queue(server_job);
      return ret;
    }

    break;

  case GEARMAN_COMMAND_WORK_DATA:
  case GEARMAN_COMMAND_WORK_WARNING:
    server_job= gearman_server_job_get(server_con->thread->server,
                                       (char *)(packet->arg[0]));
    if (server_job == NULL)
    {
      return _server_error_packet(server_con, "job_not_found",
                                  "Job given in work result not found");
    }

    /* Queue the data/warning packet for all clients. */
    ret= _server_queue_work_data(server_job, packet, packet->command);
    if (ret != GEARMAN_SUCCESS)
      return ret;

    break;

  case GEARMAN_COMMAND_WORK_STATUS:
    server_job= gearman_server_job_get(server_con->thread->server,
                                       (char *)(packet->arg[0]));
    if (server_job == NULL)
    {
      return _server_error_packet(server_con, "job_not_found",
                                  "Job given in work result not found");
    }

    /* Update job status. */
    server_job->numerator= (uint32_t)atoi((char *)(packet->arg[1]));

    /* This may not be NULL terminated, so copy to make sure it is. */
    snprintf(denominator_buffer, 11, "%.*s", (uint32_t)(packet->arg_size[2]),
             (char *)(packet->arg[2]));
    server_job->denominator= (uint32_t)atoi(denominator_buffer);

    /* Queue the status packet for all clients. */
    for (server_client= server_job->client_list; server_client;
         server_client= server_client->job_next)
    {
      ret= gearman_server_io_packet_add(server_client->con, false,
                                        GEARMAN_MAGIC_RESPONSE,
                                        GEARMAN_COMMAND_WORK_STATUS,
                                        packet->arg[0], packet->arg_size[0],
                                        packet->arg[1], packet->arg_size[1],
                                        packet->arg[2], packet->arg_size[2],
                                        NULL);
      if (ret != GEARMAN_SUCCESS)
        return ret;
    }

    break;

  case GEARMAN_COMMAND_WORK_COMPLETE:
    server_job= gearman_server_job_get(server_con->thread->server,
                                       (char *)(packet->arg[0]));
    if (server_job == NULL)
    {
      return _server_error_packet(server_con, "job_not_found",
                                  "Job given in work result not found");
    }

    /* Queue the complete packet for all clients. */
    ret= _server_queue_work_data(server_job, packet,
                                 GEARMAN_COMMAND_WORK_COMPLETE);
    if (ret != GEARMAN_SUCCESS)
      return ret;

    /* Remove from persistent queue if one exists. */
    if (server_job->options & GEARMAN_SERVER_JOB_QUEUED &&
        gearman->queue_done_fn != NULL)
    {
      ret= (*(gearman->queue_done_fn))(gearman, (void *)gearman->queue_fn_arg,
                                      server_job->unique,
                                      (size_t)strlen(server_job->unique),
                                      server_job->function->function_name,
                                      server_job->function->function_name_size);
      if (ret != GEARMAN_SUCCESS)
        return ret;
    }

    /* Job is done, remove it. */
    gearman_server_job_free(server_job);
    break;

  case GEARMAN_COMMAND_WORK_EXCEPTION:
    server_job= gearman_server_job_get(server_con->thread->server,
                                       (char *)(packet->arg[0]));
    if (server_job == NULL)
    {
      return _server_error_packet(server_con, "job_not_found",
                                  "Job given in work result not found");
    }

    /* Queue the exception packet for all clients. */
    ret= _server_queue_work_data(server_job, packet,
                                 GEARMAN_COMMAND_WORK_EXCEPTION);
    if (ret != GEARMAN_SUCCESS)
      return ret;
    break;

  case GEARMAN_COMMAND_WORK_FAIL:
    /* This may not be NULL terminated, so copy to make sure it is. */
    snprintf(job_handle, GEARMAN_JOB_HANDLE_SIZE, "%.*s",
             (uint32_t)(packet->arg_size[0]), (char *)(packet->arg[0]));

    server_job= gearman_server_job_get(server_con->thread->server, job_handle);
    if (server_job == NULL)
    {
      return _server_error_packet(server_con, "job_not_found",
                                  "Job given in work result not found");
    }

    /* Queue the fail packet for all clients. */
    for (server_client= server_job->client_list; server_client;
         server_client= server_client->job_next)
    {
      ret= gearman_server_io_packet_add(server_client->con, false,
                                        GEARMAN_MAGIC_RESPONSE,
                                        GEARMAN_COMMAND_WORK_FAIL,
                                        packet->arg[0], packet->arg_size[0],
                                        NULL);
      if (ret != GEARMAN_SUCCESS)
        return ret;
    }

    /* Remove from persistent queue if one exists. */
    if (server_job->options & GEARMAN_SERVER_JOB_QUEUED &&
        gearman->queue_done_fn != NULL)
    {
      ret= (*(gearman->queue_done_fn))(gearman, (void *)gearman->queue_fn_arg,
                                      server_job->unique,
                                      (size_t)strlen(server_job->unique),
                                      server_job->function->function_name,
                                      server_job->function->function_name_size);
      if (ret != GEARMAN_SUCCESS)
        return ret;
    }

    /* Job is done, remove it. */
    gearman_server_job_free(server_job);
    break;

  case GEARMAN_COMMAND_SET_CLIENT_ID:
    gearman_server_con_set_id(server_con, (char *)(packet->arg[0]),
                              packet->arg_size[0]);
    break;

  case GEARMAN_COMMAND_TEXT:
    return _server_run_text(server_con, packet);

  case GEARMAN_COMMAND_UNUSED:
  case GEARMAN_COMMAND_NOOP:
  case GEARMAN_COMMAND_JOB_CREATED:
  case GEARMAN_COMMAND_NO_JOB:
  case GEARMAN_COMMAND_JOB_ASSIGN:
  case GEARMAN_COMMAND_ECHO_RES:
  case GEARMAN_COMMAND_ERROR:
  case GEARMAN_COMMAND_STATUS_RES:
  case GEARMAN_COMMAND_ALL_YOURS:
  case GEARMAN_COMMAND_OPTION_RES:
  case GEARMAN_COMMAND_SUBMIT_JOB_SCHED:
  case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH:
  case GEARMAN_COMMAND_JOB_ASSIGN_UNIQ:
  case GEARMAN_COMMAND_MAX:
  default:
    return _server_error_packet(server_con, "bad_command",
                                "Command not expected");
  }

  return GEARMAN_SUCCESS;
}