Exemplo n.º 1
0
void gearman_server_free(gearman_server_st *server)
{
  uint32_t key;
  gearman_server_packet_st *packet;
  gearman_server_job_st *job;
  gearman_server_client_st *client;
  gearman_server_worker_st *worker;

  /* All threads should be cleaned up before calling this. */
  assert(server->thread_list == NULL);

  for (key= 0; key < GEARMAN_JOB_HASH_SIZE; key++)
  {
    while (server->job_hash[key] != NULL)
      gearman_server_job_free(server->job_hash[key]);
  }

  while (server->function_list != NULL)
    gearman_server_function_free(server->function_list);

  while (server->free_packet_list != NULL)
  {
    packet= server->free_packet_list;
    server->free_packet_list= packet->next;
    free(packet);
  }

  while (server->free_job_list != NULL)
  {
    job= server->free_job_list;
    server->free_job_list= job->next;
    free(job);
  }

  while (server->free_client_list != NULL)
  {
    client= server->free_client_list;
    server->free_client_list= client->con_next;
    free(client);
  }

  while (server->free_worker_list != NULL)
  {
    worker= server->free_worker_list;
    server->free_worker_list= worker->con_next;
    free(worker);
  }

  if (server->gearman != NULL)
    gearman_free(server->gearman);

  if (server->options & GEARMAN_SERVER_ALLOCATED)
    free(server);
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
gearman_server_job_st *
gearman_server_job_add(gearman_server_st *server, const char *function_name,
                       size_t function_name_size, const char *unique,
                       size_t unique_size, const void *data, size_t data_size,
                       gearman_job_priority_t priority,
                       gearman_server_client_st *server_client,
                       gearman_return_t *ret_ptr)
{
  gearman_server_job_st *server_job;
  gearman_server_function_st *server_function;
  uint32_t key;

  server_function= gearman_server_function_get(server, function_name,
                                               function_name_size);
  if (server_function == NULL)
  {
    *ret_ptr= GEARMAN_MEMORY_ALLOCATION_FAILURE;
    return NULL;
  }

  if (unique_size == 0)
    server_job= NULL;
  else
  {
    if (unique_size == 1 && *unique ==  '-')
    {
      if (data_size == 0)
        server_job= NULL;
      else
      {
        /* Look up job via unique data when unique = '-'. */
        key= _server_job_hash(data, data_size);
        server_job= _server_job_get_unique(server, key, server_function, data,
                                           data_size);
      }
    }
    else
    {
      /* Look up job via unique ID first to make sure it's not a duplicate. */
      key= _server_job_hash(unique, unique_size);
      server_job= _server_job_get_unique(server, key, server_function, unique,
                                         0);
    }
  }

  if (server_job == NULL)
  {
    if (server_function->max_queue_size > 0 &&
        server_function->job_total >= server_function->max_queue_size)
    {
      *ret_ptr= GEARMAN_JOB_QUEUE_FULL;
      return NULL;
    }

    server_job= gearman_server_job_create(server, NULL);
    if (server_job == NULL)
    {
      *ret_ptr= GEARMAN_MEMORY_ALLOCATION_FAILURE;
      return NULL;
    }

    server_job->priority= priority;

    server_job->function= server_function;
    server_function->job_total++;

    snprintf(server_job->job_handle, GEARMAN_JOB_HANDLE_SIZE, "%s:%u",
             server->job_handle_prefix, server->job_handle_count);
    snprintf(server_job->unique, GEARMAN_UNIQUE_SIZE, "%.*s",
             (uint32_t)unique_size, unique);
    server->job_handle_count++;
    server_job->data= data;
    server_job->data_size= data_size;

    server_job->unique_key= key;
    key= key % GEARMAN_JOB_HASH_SIZE;
    GEARMAN_HASH_ADD(server->unique, key, server_job, unique_)

    key= _server_job_hash(server_job->job_handle,
                          strlen(server_job->job_handle));
    server_job->job_handle_key= key;
    key= key % GEARMAN_JOB_HASH_SIZE;
    GEARMAN_HASH_ADD(server->job, key, server_job,)

    *ret_ptr= gearman_server_job_queue(server_job);
    if (*ret_ptr != GEARMAN_SUCCESS)
    {
      gearman_server_job_free(server_job);
      return NULL;
    }
  }
  else