--- bin/gearadmin.cc 2014-02-12 08:05:28.000000000 +0800 +++ bin/gearadmin.cc 2014-08-30 00:04:41.841618677 +0800 @@ -136,13 +136,31 @@ ("port,p", boost::program_options::value(&port)->default_value(GEARMAN_DEFAULT_TCP_PORT_STRING), "Port number or service to use for connection") ("server-version", "Fetch the version number for the server.") ("server-verbose", "Fetch the verbose setting for the server.") - ("create-function", boost::program_options::value(), "Create the function from the server.") - ("cancel-job", boost::program_options::value(), "Remove a given job from the server's queue") + ("config-server", boost::program_options::value >()->multitoken()->zero_tokens(), "Config the server's job_retries, job_retries_warn, job_count_max, job_count_max_interval, worker_count_min, worker_count_min_interval, worker_wakeup, max_queue_size_0, max_queue_size_1, max_queue_size_2.") + ("config-function", boost::program_options::value >()->multitoken(), "Config the function's job_retries, job_retries_warn, job_count_max, job_count_max_interval, worker_count_min, worker_count_min_interval, worker_wakeup, max_queue_size_0, max_queue_size_1, max_queue_size_2.") + ("config-functions", boost::program_options::value >()->multitoken()->zero_tokens(), "Config the functions's job_retries, job_retries_warn, job_count_max, job_count_max_interval, worker_count_min, worker_count_min_interval, worker_wakeup, max_queue_size_0, max_queue_size_1, max_queue_size_2.") + ("create-function", boost::program_options::value(), "Create the function on the server.") + ("create-functions", boost::program_options::value(), "Create the functions on the server.") ("drop-function", boost::program_options::value(), "Drop the function from the server.") - ("show-unique-jobs", "Show unique jobs on server.") - ("show-jobs", "Show all jobs on the server.") + ("drop-functions", boost::program_options::value >()->multitoken()->zero_tokens(), "Drop the functions from the server.") + ("cancel-unique-job", boost::program_options::value(), "Cancel a given unique job in the server's queue") + ("cancel-job", boost::program_options::value(), "Cancel a given handle job in the server's queue") + ("cancel-unique-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Cancel unique jobs in the server's queue. ARG can be uniques (separated by ',' . '-' if there are functions but no unique) and functions (separated by ',') .") + ("cancel-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Cancel handle jobs in the server's queue. ARG can be handles (separated by ',' . '-' if there are functions but no handle) and functions (separated by ',') .") + ("clean-unique-job", boost::program_options::value(), "Clean a given canceled unique job from the server's queue") + ("clean-job", boost::program_options::value(), "Clean a given canceled handle job from the server's queue") + ("clean-unique-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Clean canceled unique jobs from the server's queue. ARG can be uniques (separated by ',' . '-' if there are functions but no unique) and functions (separated by ',') .") + ("clean-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Clean canceled handle jobs from the server's queue. ARG can be handles (separated by ',' . '-' if there are functions but no handle) and functions (separated by ',') .") + ("restore-unique-job", boost::program_options::value(), "Restore a given canceled unique job in the server's queue.") + ("restore-job", boost::program_options::value(), "Restore a given canceled handle job in the server's queue.") + ("restore-unique-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Restore canceled unique jobs in the server's queue. ARG can be uniques (separated by ',' . '-' if there are functions but no unique) and functions (separated by ',') .") + ("restore-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Restore canceled handle jobs in the server's queue. ARG can be handles (separated by ',' . '-' if there are functions but no handle) and functions (separated by ',') .") + ("show-unique-job", boost::program_options::value(), "Show a given unique job on the server.") + ("show-job", boost::program_options::value(), "Show a given handle job on the server.") + ("show-unique-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Show unique jobs on the server. ARG can be uniques (separated by ',' . '-' if there are functions but no unique) and functions (separated by ',') .") + ("show-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Show handle jobs on the server. ARG can be handles (separated by ',' . '-' if there are functions but no handle) and functions (separated by ',') .") ("getpid", "Get Process ID for the server.") - ("status", "Status for the server.") + ("status", boost::program_options::value >()->multitoken()->zero_tokens(), "Status for the server or functions in the ARG separated by ',' .") ("workers", "Workers for the server.") ("shutdown", "Shutdown server.") ("ssl,S", "Enable SSL connections.") @@ -176,16 +194,34 @@ } if (vm.count("server-version") == 0 and - vm.count("server-verbose") == 0 and - vm.count("create-function") == 0 and - vm.count("drop-function") == 0 and - vm.count("cancel-job") == 0 and - vm.count("show-unique-jobs") == 0 and - vm.count("show-jobs") == 0 and - vm.count("getpid") == 0 and - vm.count("status") == 0 and - vm.count("workers") == 0 and - vm.count("shutdown") == 0) + vm.count("server-verbose") == 0 and + vm.count("config-server") == 0 and + vm.count("config-function") == 0 and + vm.count("config-functions") == 0 and + vm.count("create-function") == 0 and + vm.count("create-functions") == 0 and + vm.count("drop-function") == 0 and + vm.count("drop-functions") == 0 and + vm.count("cancel-unique-job") == 0 and + vm.count("cancel-job") == 0 and + vm.count("cancel-unique-jobs") == 0 and + vm.count("cancel-jobs") == 0 and + vm.count("clean-unique-job") == 0 and + vm.count("clean-job") == 0 and + vm.count("clean-unique-jobs") == 0 and + vm.count("clean-jobs") == 0 and + vm.count("restore-unique-job") == 0 and + vm.count("restore-job") == 0 and + vm.count("restore-unique-jobs") == 0 and + vm.count("restore-jobs") == 0 and + vm.count("show-unique-job") == 0 and + vm.count("show-job") == 0 and + vm.count("show-unique-jobs") == 0 and + vm.count("show-jobs") == 0 and + vm.count("getpid") == 0 and + vm.count("status") == 0 and + vm.count("workers") == 0 and + vm.count("shutdown") == 0) { std::cout << "No option execution operation given." << std::endl << std::endl; std::cout << desc << std::endl; @@ -199,7 +235,14 @@ if (vm.count("status")) { - instance.push(new util::Operation(util_literal_param("status\r\n"))); + std::string execute(util_literal_param("status")); + std::vector stat_argv= vm["status"].as >(); + for (size_t i= 0; i < stat_argv.size(); i++) + { + execute.append(' ' + stat_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); } if (vm.count("workers")) @@ -217,6 +260,14 @@ instance.push(new util::Operation(util_literal_param("verbose\r\n"))); } + if (vm.count("cancel-unique-job")) + { + std::string execute(util_literal_param("cancel unique job ")); + execute.append(vm["cancel-unique-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + if (vm.count("cancel-job")) { std::string execute(util_literal_param("cancel job ")); @@ -225,14 +276,148 @@ instance.push(new util::Operation(execute.c_str(), execute.size())); } + if (vm.count("cancel-unique-jobs")) + { + std::string execute(util_literal_param("cancel unique jobs")); + std::vector jobs_argv= vm["cancel-unique-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("cancel-jobs")) + { + std::string execute(util_literal_param("cancel jobs")); + std::vector jobs_argv= vm["cancel-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("clean-unique-job")) + { + std::string execute(util_literal_param("clean unique job ")); + execute.append(vm["clean-unique-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("clean-job")) + { + std::string execute(util_literal_param("clean job ")); + execute.append(vm["clean-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("clean-unique-jobs")) + { + std::string execute(util_literal_param("clean unique jobs")); + std::vector jobs_argv= vm["clean-unique-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("clean-jobs")) + { + std::string execute(util_literal_param("clean jobs")); + std::vector jobs_argv= vm["clean-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("restore-unique-job")) + { + std::string execute(util_literal_param("restore unique job ")); + execute.append(vm["restore-unique-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("restore-job")) + { + std::string execute(util_literal_param("restore job ")); + execute.append(vm["restore-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("restore-unique-jobs")) + { + std::string execute(util_literal_param("restore unique jobs")); + std::vector jobs_argv= vm["restore-unique-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("restore-jobs")) + { + std::string execute(util_literal_param("restore jobs")); + std::vector jobs_argv= vm["restore-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("show-unique-job")) + { + std::string execute(util_literal_param("show unique job ")); + execute.append(vm["show-unique-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("show-job")) + { + std::string execute(util_literal_param("show job ")); + execute.append(vm["show-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + if (vm.count("show-unique-jobs")) { - instance.push(new util::Operation(util_literal_param("show unique jobs\r\n"))); + std::string execute(util_literal_param("show unique jobs")); + std::vector jobs_argv= vm["show-unique-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); } if (vm.count("show-jobs")) { - instance.push(new util::Operation(util_literal_param("show jobs\r\n"))); + std::string execute(util_literal_param("show jobs")); + std::vector jobs_argv= vm["show-jobs"].as >(); + for (size_t i= 0; i < jobs_argv.size(); i++) + { + execute.append(' ' + jobs_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); } if (vm.count("drop-function")) @@ -243,6 +428,18 @@ instance.push(new util::Operation(execute.c_str(), execute.size())); } + if (vm.count("drop-functions")) + { + std::string execute(util_literal_param("drop functions")); + std::vector func_argv= vm["drop-functions"].as >(); + for (size_t i= 0; i < func_argv.size(); i++) + { + execute.append(' ' + func_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + if (vm.count("create-function")) { std::string execute(util_literal_param("create function ")); @@ -250,6 +447,50 @@ execute.append("\r\n"); instance.push(new util::Operation(execute.c_str(), execute.size())); } + + if (vm.count("create-functions")) + { + std::string execute(util_literal_param("create functions ")); + execute.append(vm["create-functions"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("config-function")) + { + std::string execute(util_literal_param("config function")); + std::vector func_argv= vm["config-function"].as >(); + for (size_t i= 0; i < func_argv.size(); i++) + { + execute.append(' ' + func_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("config-functions")) + { + std::string execute(util_literal_param("config functions")); + std::vector func_argv= vm["config-functions"].as >(); + for (size_t i= 0; i < func_argv.size(); i++) + { + execute.append(' ' + func_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("config-server")) + { + std::string execute(util_literal_param("config server")); + std::vector serv_argv= vm["config-server"].as >(); + for (size_t i= 0; i < serv_argv.size(); i++) + { + execute.append(' ' + serv_argv[i]); + } + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } if (vm.count("getpid")) { --- gearmand/gearmand.cc 2014-02-12 08:05:28.000000000 +0800 +++ gearmand/gearmand.cc 2014-08-29 22:57:10.711793676 +0800 @@ -107,8 +107,13 @@ int backlog; rlim_t fds= 0; - uint32_t job_retries; - uint32_t worker_wakeup; + + struct Options_st options; + std::string job_retries_action; // Set action for job retries reaches job_retries. + std::string job_retries_warn_action; // Set action for job retries reaches job_retries_warn. + std::string job_count_max_action; // Set action for job count more than job_count_max. + std::string worker_count_min_action; // Set action for worker count less than worker_count_min. + std::string worker_failed_action; // Set action for worker failed. std::string host; std::string user; @@ -140,6 +145,12 @@ ("backlog,b", boost::program_options::value(&backlog)->default_value(32), "Number of backlog connections for listen.") + ("config-file", boost::program_options::value(&config_file)->default_value(GEARMAND_CONFIG), + "Can be specified with '@name', too") + + ("coredump", boost::program_options::bool_switch(&opt_coredump)->default_value(false), + "Whether to create a core dump for uncaught signals.") + ("daemon,d", boost::program_options::bool_switch(&opt_daemon)->default_value(false), "Daemon, detach and run in the background.") @@ -149,16 +160,34 @@ ("file-descriptors,f", boost::program_options::value(&fds), "Number of file descriptors to allow for the process (total connections will be slightly less). Default is max allowed for user.") + ("hashtable-buckets", boost::program_options::value(&hashtable_buckets)->default_value(GEARMAND_DEFAULT_HASH_SIZE), + "Number of buckets in the internal job hash tables. The default of 991 works well for about three million jobs in queue. If the number of jobs in the queue at any time will exceed three million, use proportionally larger values (991 * # of jobs / 3M). For example, to accomodate 2^32 jobs, use 1733003. This will consume ~26MB of extra memory. Gearmand cannot support more than 2^32 jobs in queue at this time.") + ("help,h", "Print this help menu.") - ("job-retries,j", boost::program_options::value(&job_retries)->default_value(0), - "Number of attempts to run the job before the job server removes it. This is helpful to ensure a bad job does not crash all available workers. Default is no limit.") + ("job-count-max", boost::program_options::value(&(options.job_count_max))->default_value(0), + "Number of jobs per function before the job server gives a warning about it. Default(0) means no action.") + + ("job-count-max-interval", boost::program_options::value(&(options.job_count_max_interval))->default_value(0), + "Interval between actions of testing and warning about job-count-max. Default(0) means no action.") + + ("job-count-max-action", boost::program_options::value(&job_count_max_action)->default_value(""), + "Program to be run when Number of jobs per function is more than job-count-max. Default('') means no action.") ("job-handle-prefix", boost::program_options::value(&job_handle_prefix), "Prefix used to generate a job handle string. If not provided, the default \"H:\" is used.") - ("hashtable-buckets", boost::program_options::value(&hashtable_buckets)->default_value(GEARMAND_DEFAULT_HASH_SIZE), - "Number of buckets in the internal job hash tables. The default of 991 works well for about three million jobs in queue. If the number of jobs in the queue at any time will exceed three million, use proportionally larger values (991 * # of jobs / 3M). For example, to accomodate 2^32 jobs, use 1733003. This will consume ~26MB of extra memory. Gearmand cannot support more than 2^32 jobs in queue at this time.") + ("job-retries,j", boost::program_options::value(&(options.job_retries))->default_value(0), + "Number of attempts to run the job before the job server removes it. This is helpful to ensure a bad job does not crash all available workers. Default is no limit.") + + ("job-retries-action", boost::program_options::value(&job_retries_action)->default_value(""), + "Program to be run when the job's attempts reaches job-retries. Default('') means no action.") + + ("job-retries-warn", boost::program_options::value(&(options.job_retries_warn))->default_value(0), + "Number of attempts to run the job before the job server gives a warning about it. Default(0) means no action.") + + ("job-retries-warn-action", boost::program_options::value(&job_retries_warn_action)->default_value(""), + "Program to be run when the job's attempts reaches job-retries-warn. Default('') means no action.") ("keepalive", boost::program_options::bool_switch(&opt_keepalive)->default_value(false), "Enable keepalive on sockets.") @@ -178,27 +207,30 @@ ("listen,L", boost::program_options::value(&host), "Address the server should listen on. Default is INADDR_ANY.") + ("max_queue_size_0", boost::program_options::value(&(options.max_queue_size[0]))->default_value(0), + "Max queue size for priority 0.") + + ("max_queue_size_1", boost::program_options::value(&(options.max_queue_size[1]))->default_value(0), + "Max queue size for priority 1.") + + ("max_queue_size_2", boost::program_options::value(&(options.max_queue_size[2]))->default_value(0), + "Max queue size for priority 2.") + ("pid-file,P", boost::program_options::value(&pid_file)->default_value(GEARMAND_PID), "File to write process ID out to.") ("protocol,r", boost::program_options::value(&protocol), "Load protocol module.") - ("round-robin,R", boost::program_options::bool_switch(&opt_round_robin)->default_value(false), - "Assign work in round-robin order per worker connection. The default is to assign work in the order of functions added by the worker.") - ("queue-type,q", boost::program_options::value(&queue_type)->default_value("builtin"), "Persistent queue type to use.") - ("config-file", boost::program_options::value(&config_file)->default_value(GEARMAND_CONFIG), - "Can be specified with '@name', too") + ("round-robin,R", boost::program_options::bool_switch(&opt_round_robin)->default_value(false), + "Assign work in round-robin order per worker connection. The default is to assign work in the order of functions added by the worker.") ("syslog", boost::program_options::bool_switch(&opt_syslog)->default_value(false), "Use syslog.") - ("coredump", boost::program_options::bool_switch(&opt_coredump)->default_value(false), - "Whether to create a core dump for uncaught signals.") - ("threads,t", boost::program_options::value(&threads)->default_value(4), "Number of I/O threads to use, 0 means that gearmand will try to guess the maximum number it can use. Default=4.") @@ -209,7 +241,20 @@ "Set verbose level (FATAL, ALERT, CRITICAL, ERROR, WARNING, NOTICE, INFO, DEBUG).") ("version,V", "Display the version of gearmand and exit.") - ("worker-wakeup,w", boost::program_options::value(&worker_wakeup)->default_value(0), + + ("worker-count-min", boost::program_options::value(&(options.worker_count_min))->default_value(0), + "Number of workers per function before the job server gives a warning about it. Default(0) means no action.") + + ("worker-count-min-interval", boost::program_options::value(&(options.worker_count_min_interval))->default_value(0), + "Interval between actions of testing and warning about worker-count-min. Default(0) means no action.") + + ("worker-count-min-action", boost::program_options::value(&worker_count_min_action)->default_value(""), + "Program to be run when Number of workers per function is less than worker-count-min. Default('') means no action.") + + ("worker-failed-action", boost::program_options::value(&worker_failed_action)->default_value(""), + "Program to be run when worker failed or disconnected. Default is no action.") + + ("worker-wakeup,w", boost::program_options::value(&(options.worker_wakeup))->default_value(0), "Number of workers to wakeup for each job received. The default is to wakeup all available workers.") ; @@ -390,12 +435,16 @@ gearmand_st *_gearmand= gearmand_create(gearmand_config, host.empty() ? NULL : host.c_str(), threads, backlog, - static_cast(job_retries), job_handle_prefix.empty() ? NULL : job_handle_prefix.c_str(), - static_cast(worker_wakeup), _log, &log_info, verbose, opt_round_robin, opt_exceptions, - hashtable_buckets); + hashtable_buckets, + options, + job_retries_action.empty() ? NULL : job_retries_action.c_str(), + job_retries_warn_action.empty() ? NULL : job_retries_warn_action.c_str(), + job_count_max_action.empty() ? NULL : job_count_max_action.c_str(), + worker_count_min_action.empty() ? NULL : worker_count_min_action.c_str(), + worker_failed_action.empty() ? NULL : worker_failed_action.c_str()); if (_gearmand == NULL) { error::message("Could not create gearmand library instance."); --- libgearman/add.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/add.cc 2014-08-03 01:52:11.415246532 +0800 @@ -63,6 +63,8 @@ switch (command) { case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH: + case GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH: + case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH: case GEARMAN_COMMAND_SUBMIT_JOB_SCHED: case GEARMAN_COMMAND_SUBMIT_JOB_BG: case GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG: @@ -257,9 +259,12 @@ break; case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH: + case GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH: + case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH: rc= libgearman::protocol::submit_epoch(task->client->universal, task->send, final_unique, + command, function, workload, when); --- libgearman/client.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/client.cc 2014-08-12 17:55:05.858785257 +0800 @@ -213,9 +213,9 @@ */ static gearman_return_t _client_do_background(gearman_client_st* client_shell, gearman_command_t command, - gearman_string_t &function, - gearman_unique_t &unique, - gearman_string_t &workload, + const char *function_name, + const char *unique, + const void *workload_str, size_t workload_size, gearman_job_handle_t job_handle) { if (client_shell == NULL or client_shell->impl() == NULL) @@ -226,19 +226,23 @@ Client* client= client_shell->impl(); client->universal.reset_error(); - if (gearman_size(function) == 0) + if (function_name == NULL or strlen(function_name) == 0) { return gearman_error(client->universal, GEARMAN_INVALID_ARGUMENT, "function argument was empty"); } client->_do_handle[0]= 0; // Reset the job_handle we store in client + gearman_string_t function= { gearman_string_param_cstr(function_name) }; + gearman_unique_t local_unique= gearman_unique_make(unique, unique ? strlen(unique) : 0); + gearman_string_t workload= { static_cast(workload_str), workload_size }; + client->universal.options.no_new_data= true; gearman_task_st* do_task= add_task(*client, NULL, client, command, function, - unique, + local_unique, workload, time_t(0), gearman_actions_do_default()); @@ -266,6 +270,69 @@ return ret; } +/* + Real epoch do function. +*/ +static gearman_return_t _client_do_epoch(gearman_client_st* client_shell, + gearman_command_t command, + const char *function_name, + const char *unique, + const void *workload_str, size_t workload_size, + time_t when, + gearman_job_handle_t job_handle) +{ + if (client_shell == NULL or client_shell->impl() == NULL) + { + return GEARMAN_INVALID_ARGUMENT; + } + + Client* client= client_shell->impl(); + client->universal.reset_error(); + + if (function_name == NULL or strlen(function_name) == 0) + { + return gearman_error(client->universal, GEARMAN_INVALID_ARGUMENT, "function argument was empty"); + } + + client->_do_handle[0]= 0; // Reset the job_handle we store in client + + gearman_string_t function= { gearman_string_param_cstr(function_name) }; + gearman_unique_t local_unique= gearman_unique_make(unique, unique ? strlen(unique) : 0); + gearman_string_t workload= { static_cast(workload_str), workload_size }; + + client->universal.options.no_new_data= true; + gearman_task_st* do_task= add_task(*client, NULL, + client, + command, + function, + local_unique, + workload, + when, + gearman_actions_do_default()); + client->universal.options.no_new_data= false; + + if (do_task == NULL) + { + gearman_task_free(do_task); + return client->universal.error_code(); + } + assert(do_task); + do_task->impl()->type= GEARMAN_TASK_KIND_DO; + + gearman_return_t ret= gearman_client_run_block_tasks(client, do_task); + + if (job_handle) + { + strncpy(job_handle, do_task->impl()->job_handle, GEARMAN_JOB_HANDLE_SIZE); + } + strncpy(client->_do_handle, do_task->impl()->job_handle, GEARMAN_JOB_HANDLE_SIZE); + client->new_tasks= 0; + client->running_tasks= 0; + gearman_task_free(do_task); + + return ret; +} + /* * Public Definitions @@ -546,6 +613,15 @@ } } +void gearman_client_set_ssl(gearman_client_st *client_shell, bool ssl, + const char *ca_file, const char *certificate, const char *key_file) +{ + if (client_shell && client_shell->impl()) + { + gearman_universal_set_ssl(client_shell->impl()->universal, ssl, ca_file, certificate, key_file); + } +} + void *gearman_client_context(const gearman_client_st *client_shell) { if (client_shell and client_shell->impl()) @@ -599,7 +675,7 @@ { Client* client= client_shell->impl(); - if (gearman_connection_create(client->universal, host, port) == false) + if (gearman_connection_create(client->universal, host, port) == NULL) { assert(client->error_code() != GEARMAN_SUCCESS); return client->error_code(); @@ -614,7 +690,7 @@ gearman_return_t Client::add_server(const char *host, const char* service_) { - if (gearman_connection_create(universal, host, service_) == false) + if (gearman_connection_create(universal, host, service_) == NULL) { assert(error_code() != GEARMAN_SUCCESS); return error_code(); @@ -772,14 +848,10 @@ size_t workload_size, gearman_job_handle_t job_handle) { - gearman_string_t function= { gearman_string_param_cstr(function_name) }; - gearman_unique_t local_unique= gearman_unique_make(unique, unique ? strlen(unique) : 0); - gearman_string_t workload= { static_cast(workload_str), workload_size }; - return _client_do_background(client_shell, GEARMAN_COMMAND_SUBMIT_JOB_BG, - function, - local_unique, - workload, + function_name, + unique, + workload_str, workload_size, job_handle); } @@ -790,14 +862,10 @@ size_t workload_size, gearman_job_handle_t job_handle) { - gearman_string_t function= { gearman_string_param_cstr(function_name) }; - gearman_unique_t local_unique= gearman_unique_make(unique, unique ? strlen(unique) : 0); - gearman_string_t workload= { static_cast(workload_str), workload_size }; - return _client_do_background(client_shell, GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG, - function, - local_unique, - workload, + function_name, + unique, + workload_str, workload_size, job_handle); } @@ -808,17 +876,61 @@ size_t workload_size, gearman_job_handle_t job_handle) { - gearman_string_t function= { gearman_string_param_cstr(function_name) }; - gearman_unique_t local_unique= gearman_unique_make(unique, unique ? strlen(unique) : 0); - gearman_string_t workload= { static_cast(workload_str), workload_size }; - return _client_do_background(client_shell, GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG, - function, - local_unique, - workload, + function_name, + unique, + workload_str, workload_size, job_handle); } +gearman_return_t gearman_client_do_epoch(gearman_client_st *client_shell, + const char *function_name, + const char *unique, + const void *workload_str, + size_t workload_size, + time_t when, + gearman_job_handle_t job_handle) +{ + return _client_do_epoch(client_shell, GEARMAN_COMMAND_SUBMIT_JOB_EPOCH, + function_name, + unique, + workload_str, workload_size, + when, + job_handle); +} + +gearman_return_t gearman_client_do_high_epoch(gearman_client_st *client_shell, + const char *function_name, + const char *unique, + const void *workload_str, + size_t workload_size, + time_t when, + gearman_job_handle_t job_handle) +{ + return _client_do_epoch(client_shell, GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH, + function_name, + unique, + workload_str, workload_size, + when, + job_handle); +} + +gearman_return_t gearman_client_do_low_epoch(gearman_client_st *client_shell, + const char *function_name, + const char *unique, + const void *workload_str, + size_t workload_size, + time_t when, + gearman_job_handle_t job_handle) +{ + return _client_do_epoch(client_shell, GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH, + function_name, + unique, + workload_str, workload_size, + when, + job_handle); +} + gearman_status_t gearman_client_unique_status(gearman_client_st *client_shell, const char *unique, size_t unique_length) { @@ -926,27 +1038,27 @@ if (gearman_success(ret)) { - if (is_known) + if (is_known != NULL) { *is_known= do_task->impl()->options.is_known; } - if (is_running) + if (is_running != NULL) { *is_running= do_task->impl()->options.is_running; } - if (numerator) + if (numerator != NULL) { *numerator= do_task->impl()->numerator; } - if (denominator) + if (denominator != NULL) { *denominator= do_task->impl()->denominator; } - if (is_known == false and is_running == false) + if (is_known == NULL and is_running == NULL) { if (do_task->impl()->options.is_running) { @@ -960,22 +1072,22 @@ } else { - if (is_known) + if (is_known != NULL) { *is_known= false; } - if (is_running) + if (is_running != NULL) { *is_running= false; } - if (numerator) + if (numerator != NULL) { *numerator= 0; } - if (denominator) + if (denominator != NULL) { *denominator= 0; } @@ -1217,6 +1329,96 @@ } +gearman_task_st *gearman_client_add_task_epoch(gearman_client_st *client, + gearman_task_st *task, + void *context, + const char *function, + const char *unique, + const void *workload, size_t workload_size, + time_t when, + gearman_return_t *ret_ptr) +{ + gearman_return_t unused; + if (ret_ptr == NULL) + { + ret_ptr= &unused; + } + + if (client == NULL or client->impl() == NULL) + { + *ret_ptr= GEARMAN_INVALID_ARGUMENT; + return NULL; + } + + return add_task_ptr(*(client->impl()), task, context, GEARMAN_COMMAND_SUBMIT_JOB_EPOCH, + function, + unique, + workload, workload_size, + when, + *ret_ptr, + client->impl()->actions); +} + +gearman_task_st *gearman_client_add_task_high_epoch(gearman_client_st *client, + gearman_task_st *task, + void *context, + const char *function, + const char *unique, + const void *workload, size_t workload_size, + time_t when, + gearman_return_t *ret_ptr) +{ + gearman_return_t unused; + if (ret_ptr == NULL) + { + ret_ptr= &unused; + } + + if (client == NULL or client->impl() == NULL) + { + *ret_ptr= GEARMAN_INVALID_ARGUMENT; + return NULL; + } + + return add_task_ptr(*(client->impl()), task, context, GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH, + function, + unique, + workload, workload_size, + when, + *ret_ptr, + client->impl()->actions); +} + +gearman_task_st *gearman_client_add_task_low_epoch(gearman_client_st *client, + gearman_task_st *task, + void *context, + const char *function, + const char *unique, + const void *workload, size_t workload_size, + time_t when, + gearman_return_t *ret_ptr) +{ + gearman_return_t unused; + if (ret_ptr == NULL) + { + ret_ptr= &unused; + } + + if (client == NULL or client->impl() == NULL) + { + *ret_ptr= GEARMAN_INVALID_ARGUMENT; + return NULL; + } + + return add_task_ptr(*(client->impl()), task, context, GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH, + function, + unique, + workload, workload_size, + when, + *ret_ptr, + client->impl()->actions); +} + gearman_task_st *gearman_client_add_task_status(gearman_client_st *client_shell, gearman_task_st *task_shell, void *context, --- libgearman/client.hpp 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/client.hpp 2014-07-07 14:23:34.249335984 +0800 @@ -121,6 +121,7 @@ void enable_ssl() { + return; if (getenv("GEARMAND_CA_CERTIFICATE")) { gearman_client_add_options(_client, GEARMAN_CLIENT_SSL); --- libgearman/command.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/command.cc 2014-08-06 16:52:24.835443718 +0800 @@ -93,12 +93,14 @@ { "GEARMAN_GRAB_JOB_ALL", GEARMAN_COMMAND_GRAB_JOB_ALL, 0, false }, { "GEARMAN_JOB_ASSIGN_ALL", GEARMAN_COMMAND_JOB_ASSIGN_ALL, 4, true }, { "GEARMAN_GET_STATUS_UNIQUE", GEARMAN_COMMAND_GET_STATUS_UNIQUE, 1, false }, - { "GEARMAN_STATUS_RES_UNIQUE", GEARMAN_COMMAND_STATUS_RES_UNIQUE, 6, false } + { "GEARMAN_STATUS_RES_UNIQUE", GEARMAN_COMMAND_STATUS_RES_UNIQUE, 6, false }, + { "GEARMAN_SUBMIT_JOB_HIGH_EPOCH", GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH, 3, true }, + { "GEARMAN_SUBMIT_JOB_LOW_EPOCH", GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH, 3, true } }; const char *gearman_strcommand(gearman_command_t command) { - if ((command >= GEARMAN_COMMAND_TEXT) and (command <= GEARMAN_COMMAND_STATUS_RES_UNIQUE)) + if ((command >= GEARMAN_COMMAND_TEXT) and (command < GEARMAN_COMMAND_MAX)) { const char* str= gearmand_command_info_list[command].name; @@ -112,7 +114,7 @@ const char *gearman_enum_strcommand(gearman_command_t command) { - if ((command >= GEARMAN_COMMAND_TEXT) and (command <= GEARMAN_COMMAND_STATUS_RES_UNIQUE)) + if ((command >= GEARMAN_COMMAND_TEXT) and (command < GEARMAN_COMMAND_MAX)) { return gearmand_command_info_list[command].name; } --- libgearman/command.gperf 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/command.gperf 2014-08-02 20:00:02.315307073 +0800 @@ -106,4 +106,6 @@ JOB_ASSIGN_ALL, GEARMAN_COMMAND_JOB_ASSIGN_ALL GET_STATUS_UNIQUE, GEARMAN_COMMAND_GET_STATUS_UNIQUE STATUS_RES_UNIQUE, GEARMAN_COMMAND_STATUS_RES_UNIQUE +SUBMIT_JOB_HIGH_EPOCH, GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH +SUBMIT_JOB_LOW_EPOCH, GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH %% --- libgearman/command.hpp 2014-02-12 08:06:02.000000000 +0800 +++ libgearman/command.hpp 2014-08-02 20:06:36.115304168 +0800 @@ -85,12 +85,12 @@ }; #include -#define TOTAL_KEYWORDS 43 +#define TOTAL_KEYWORDS 45 #define MIN_WORD_LENGTH 4 #define MAX_WORD_LENGTH 28 #define MIN_HASH_VALUE 4 -#define MAX_HASH_VALUE 73 -/* maximum key range = 70, duplicates = 0 */ +#define MAX_HASH_VALUE 75 +/* maximum key range = 72, duplicates = 0 */ #ifndef GPERF_DOWNCASE #define GPERF_DOWNCASE 1 @@ -150,32 +150,32 @@ { static const unsigned char asso_values[] = { - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 35, 5, 25, 10, 25, - 74, 0, 25, 74, 5, 74, 10, 74, 0, 15, - 30, 40, 15, 10, 0, 0, 74, 0, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 35, 5, 25, - 10, 25, 74, 0, 25, 74, 5, 74, 10, 74, - 0, 15, 30, 40, 15, 10, 0, 0, 74, 0, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74, 74, 74, 74, 74, - 74, 74, 74, 74, 74, 74 + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 25, 5, 25, 25, 25, + 76, 0, 10, 76, 10, 76, 5, 76, 45, 30, + 0, 20, 45, 10, 0, 0, 76, 0, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 25, 5, 25, + 25, 25, 76, 0, 10, 76, 10, 76, 5, 76, + 45, 30, 0, 20, 45, 10, 0, 0, 76, 0, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76 }; return len + asso_values[(unsigned char)str[len - 1]] + asso_values[(unsigned char)str[0]]; } @@ -184,34 +184,26 @@ { #line 66 "libgearman/command.gperf" {"TEXT", GEARMAN_COMMAND_TEXT}, -#line 76 "libgearman/command.gperf" - {"NO_JOB", GEARMAN_COMMAND_NO_JOB}, +#line 70 "libgearman/command.gperf" + {"PRE_SLEEP", GEARMAN_COMMAND_PRE_SLEEP}, #line 95 "libgearman/command.gperf" {"WORK_WARNING", GEARMAN_COMMAND_WORK_WARNING }, #line 75 "libgearman/command.gperf" {"GRAB_JOB", GEARMAN_COMMAND_GRAB_JOB}, -#line 91 "libgearman/command.gperf" - {"WORK_EXCEPTION", GEARMAN_COMMAND_WORK_EXCEPTION }, -#line 77 "libgearman/command.gperf" - {"JOB_ASSIGN", GEARMAN_COMMAND_JOB_ASSIGN }, -#line 71 "libgearman/command.gperf" - {"UNUSED", GEARMAN_COMMAND_UNUSED}, #line 80 "libgearman/command.gperf" {"WORK_FAIL",GEARMAN_COMMAND_WORK_FAIL}, +#line 105 "libgearman/command.gperf" + {"GRAB_JOB_ALL", GEARMAN_COMMAND_GRAB_JOB_ALL }, #line 81 "libgearman/command.gperf" {"GET_STATUS",GEARMAN_COMMAND_GET_STATUS}, #line 78 "libgearman/command.gperf" {"WORK_STATUS", GEARMAN_COMMAND_WORK_STATUS}, -#line 105 "libgearman/command.gperf" - {"GRAB_JOB_ALL", GEARMAN_COMMAND_GRAB_JOB_ALL }, #line 84 "libgearman/command.gperf" {"SUBMIT_JOB_BG", GEARMAN_COMMAND_SUBMIT_JOB_BG }, #line 99 "libgearman/command.gperf" {"SUBMIT_JOB_LOW", GEARMAN_COMMAND_SUBMIT_JOB_LOW }, #line 73 "libgearman/command.gperf" {"SUBMIT_JOB", GEARMAN_COMMAND_SUBMIT_JOB }, -#line 74 "libgearman/command.gperf" - {"JOB_CREATED", GEARMAN_COMMAND_JOB_CREATED}, #line 100 "libgearman/command.gperf" {"SUBMIT_JOB_LOW_BG", GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG }, #line 98 "libgearman/command.gperf" @@ -220,54 +212,66 @@ {"JOB_ASSIGN_ALL", GEARMAN_COMMAND_JOB_ASSIGN_ALL }, #line 86 "libgearman/command.gperf" {"STATUS_RES", GEARMAN_COMMAND_STATUS_RES}, +#line 71 "libgearman/command.gperf" + {"UNUSED", GEARMAN_COMMAND_UNUSED}, #line 103 "libgearman/command.gperf" {"SUBMIT_REDUCE_JOB", GEARMAN_COMMAND_SUBMIT_REDUCE_JOB}, -#line 88 "libgearman/command.gperf" - {"SET_CLIENT_ID", GEARMAN_COMMAND_SET_CLIENT_ID}, -#line 72 "libgearman/command.gperf" - {"NOOP", GEARMAN_COMMAND_NOOP}, -#line 93 "libgearman/command.gperf" - {"OPTION_RES", GEARMAN_COMMAND_OPTION_RES}, -#line 101 "libgearman/command.gperf" - {"SUBMIT_JOB_SCHED", GEARMAN_COMMAND_SUBMIT_JOB_SCHED }, +#line 96 "libgearman/command.gperf" + {"GRAB_JOB_UNIQ", GEARMAN_COMMAND_GRAB_JOB_UNIQ}, +#line 94 "libgearman/command.gperf" + {"WORK_DATA", GEARMAN_COMMAND_WORK_DATA }, +#line 87 "libgearman/command.gperf" + {"SUBMIT_JOB_HIGH", GEARMAN_COMMAND_SUBMIT_JOB_HIGH }, +#line 102 "libgearman/command.gperf" + {"SUBMIT_JOB_EPOCH", GEARMAN_COMMAND_SUBMIT_JOB_EPOCH }, #line 79 "libgearman/command.gperf" {"WORK_COMPLETE", GEARMAN_COMMAND_WORK_COMPLETE }, #line 89 "libgearman/command.gperf" {"CAN_DO_TIMEOUT", GEARMAN_COMMAND_CAN_DO_TIMEOUT}, -#line 69 "libgearman/command.gperf" - {"RESET_ABILITIES", GEARMAN_COMMAND_RESET_ABILITIES}, +#line 110 "libgearman/command.gperf" + {"SUBMIT_JOB_LOW_EPOCH", GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH }, +#line 109 "libgearman/command.gperf" + {"SUBMIT_JOB_HIGH_EPOCH", GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH }, #line 107 "libgearman/command.gperf" {"GET_STATUS_UNIQUE", GEARMAN_COMMAND_GET_STATUS_UNIQUE}, #line 83 "libgearman/command.gperf" {"ECHO_RES", GEARMAN_COMMAND_ECHO_RES }, -#line 94 "libgearman/command.gperf" - {"WORK_DATA", GEARMAN_COMMAND_WORK_DATA }, -#line 85 "libgearman/command.gperf" - {"ERROR", GEARMAN_COMMAND_ERROR}, -#line 67 "libgearman/command.gperf" - {"CAN_DO", GEARMAN_COMMAND_CAN_DO}, -#line 68 "libgearman/command.gperf" - {"CANT_DO", GEARMAN_COMMAND_CANT_DO}, -#line 104 "libgearman/command.gperf" - {"SUBMIT_REDUCE_JOB_BACKGROUND", GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BACKGROUND}, -#line 87 "libgearman/command.gperf" - {"SUBMIT_JOB_HIGH", GEARMAN_COMMAND_SUBMIT_JOB_HIGH }, -#line 102 "libgearman/command.gperf" - {"SUBMIT_JOB_EPOCH", GEARMAN_COMMAND_SUBMIT_JOB_EPOCH }, -#line 108 "libgearman/command.gperf" - {"STATUS_RES_UNIQUE", GEARMAN_COMMAND_STATUS_RES_UNIQUE}, -#line 96 "libgearman/command.gperf" - {"GRAB_JOB_UNIQ", GEARMAN_COMMAND_GRAB_JOB_UNIQ}, #line 90 "libgearman/command.gperf" {"ALL_YOURS", GEARMAN_COMMAND_ALL_YOURS}, #line 97 "libgearman/command.gperf" {"JOB_ASSIGN_UNIQ", GEARMAN_COMMAND_JOB_ASSIGN_UNIQ }, +#line 74 "libgearman/command.gperf" + {"JOB_CREATED", GEARMAN_COMMAND_JOB_CREATED}, +#line 88 "libgearman/command.gperf" + {"SET_CLIENT_ID", GEARMAN_COMMAND_SET_CLIENT_ID}, +#line 72 "libgearman/command.gperf" + {"NOOP", GEARMAN_COMMAND_NOOP}, +#line 93 "libgearman/command.gperf" + {"OPTION_RES", GEARMAN_COMMAND_OPTION_RES}, +#line 101 "libgearman/command.gperf" + {"SUBMIT_JOB_SCHED", GEARMAN_COMMAND_SUBMIT_JOB_SCHED }, +#line 108 "libgearman/command.gperf" + {"STATUS_RES_UNIQUE", GEARMAN_COMMAND_STATUS_RES_UNIQUE}, +#line 82 "libgearman/command.gperf" + {"ECHO_REQ", GEARMAN_COMMAND_ECHO_REQ }, +#line 76 "libgearman/command.gperf" + {"NO_JOB", GEARMAN_COMMAND_NO_JOB}, +#line 91 "libgearman/command.gperf" + {"WORK_EXCEPTION", GEARMAN_COMMAND_WORK_EXCEPTION }, #line 92 "libgearman/command.gperf" {"OPTION_REQ", GEARMAN_COMMAND_OPTION_REQ}, -#line 70 "libgearman/command.gperf" - {"PRE_SLEEP", GEARMAN_COMMAND_PRE_SLEEP}, -#line 82 "libgearman/command.gperf" - {"ECHO_REQ", GEARMAN_COMMAND_ECHO_REQ } +#line 67 "libgearman/command.gperf" + {"CAN_DO", GEARMAN_COMMAND_CAN_DO}, +#line 68 "libgearman/command.gperf" + {"CANT_DO", GEARMAN_COMMAND_CANT_DO}, +#line 104 "libgearman/command.gperf" + {"SUBMIT_REDUCE_JOB_BACKGROUND", GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BACKGROUND}, +#line 77 "libgearman/command.gperf" + {"JOB_ASSIGN", GEARMAN_COMMAND_JOB_ASSIGN }, +#line 69 "libgearman/command.gperf" + {"RESET_ABILITIES", GEARMAN_COMMAND_RESET_ABILITIES}, +#line 85 "libgearman/command.gperf" + {"ERROR", GEARMAN_COMMAND_ERROR} }; const struct gearman_command_string_st * @@ -290,8 +294,8 @@ goto compare; } break; - case 7: - if (len == 6) + case 5: + if (len == 9) { resword = &gearman_command_string_st[1]; goto compare; @@ -312,278 +316,292 @@ } break; case 10: - if (len == 14) + if (len == 9) { resword = &gearman_command_string_st[4]; goto compare; } break; - case 11: - if (len == 10) + case 13: + if (len == 12) { resword = &gearman_command_string_st[5]; goto compare; } break; - case 12: - if (len == 6) + case 16: + if (len == 10) { resword = &gearman_command_string_st[6]; goto compare; } break; - case 15: - if (len == 9) + case 17: + if (len == 11) { resword = &gearman_command_string_st[7]; goto compare; } break; - case 16: - if (len == 10) + case 19: + if (len == 13) { resword = &gearman_command_string_st[8]; goto compare; } break; - case 17: - if (len == 11) + case 20: + if (len == 14) { resword = &gearman_command_string_st[9]; goto compare; } break; - case 18: - if (len == 12) + case 21: + if (len == 10) { resword = &gearman_command_string_st[10]; goto compare; } break; - case 19: - if (len == 13) + case 23: + if (len == 17) { resword = &gearman_command_string_st[11]; goto compare; } break; - case 20: - if (len == 14) + case 24: + if (len == 18) { resword = &gearman_command_string_st[12]; goto compare; } break; - case 21: - if (len == 10) + case 25: + if (len == 14) { resword = &gearman_command_string_st[13]; goto compare; } break; - case 22: - if (len == 11) + case 26: + if (len == 10) { resword = &gearman_command_string_st[14]; goto compare; } break; - case 23: - if (len == 17) + case 27: + if (len == 6) { resword = &gearman_command_string_st[15]; goto compare; } break; - case 24: - if (len == 18) + case 28: + if (len == 17) { resword = &gearman_command_string_st[16]; goto compare; } break; - case 25: - if (len == 14) + case 29: + if (len == 13) { resword = &gearman_command_string_st[17]; goto compare; } break; - case 26: - if (len == 10) + case 30: + if (len == 9) { resword = &gearman_command_string_st[18]; goto compare; } break; - case 28: - if (len == 17) + case 31: + if (len == 15) { resword = &gearman_command_string_st[19]; goto compare; } break; - case 29: - if (len == 13) + case 32: + if (len == 16) { resword = &gearman_command_string_st[20]; goto compare; } break; - case 30: - if (len == 4) + case 34: + if (len == 13) { resword = &gearman_command_string_st[21]; goto compare; } break; - case 31: - if (len == 10) + case 35: + if (len == 14) { resword = &gearman_command_string_st[22]; goto compare; } break; - case 32: - if (len == 16) + case 36: + if (len == 20) { resword = &gearman_command_string_st[23]; goto compare; } break; - case 34: - if (len == 13) + case 37: + if (len == 21) { resword = &gearman_command_string_st[24]; goto compare; } break; - case 35: - if (len == 14) + case 38: + if (len == 17) { resword = &gearman_command_string_st[25]; goto compare; } break; - case 36: - if (len == 15) + case 39: + if (len == 8) { resword = &gearman_command_string_st[26]; goto compare; } break; - case 38: - if (len == 17) + case 40: + if (len == 9) { resword = &gearman_command_string_st[27]; goto compare; } break; - case 39: - if (len == 8) + case 41: + if (len == 15) { resword = &gearman_command_string_st[28]; goto compare; } break; - case 40: - if (len == 9) + case 42: + if (len == 11) { resword = &gearman_command_string_st[29]; goto compare; } break; - case 41: - if (len == 5) + case 44: + if (len == 13) { resword = &gearman_command_string_st[30]; goto compare; } break; - case 42: - if (len == 6) + case 45: + if (len == 4) { resword = &gearman_command_string_st[31]; goto compare; } break; - case 43: - if (len == 7) + case 46: + if (len == 10) { resword = &gearman_command_string_st[32]; goto compare; } break; - case 44: - if (len == 28) + case 47: + if (len == 16) { resword = &gearman_command_string_st[33]; goto compare; } break; - case 46: - if (len == 15) + case 48: + if (len == 17) { resword = &gearman_command_string_st[34]; goto compare; } break; - case 47: - if (len == 16) + case 49: + if (len == 8) { resword = &gearman_command_string_st[35]; goto compare; } break; - case 48: - if (len == 17) + case 52: + if (len == 6) { resword = &gearman_command_string_st[36]; goto compare; } break; - case 49: - if (len == 13) + case 55: + if (len == 14) { resword = &gearman_command_string_st[37]; goto compare; } break; - case 50: - if (len == 9) + case 56: + if (len == 10) { resword = &gearman_command_string_st[38]; goto compare; } break; - case 56: - if (len == 15) + case 57: + if (len == 6) { resword = &gearman_command_string_st[39]; goto compare; } break; - case 61: - if (len == 10) + case 58: + if (len == 7) { resword = &gearman_command_string_st[40]; goto compare; } break; - case 65: - if (len == 9) + case 59: + if (len == 28) { resword = &gearman_command_string_st[41]; goto compare; } break; - case 69: - if (len == 8) + case 61: + if (len == 10) { resword = &gearman_command_string_st[42]; goto compare; } break; + case 66: + if (len == 15) + { + resword = &gearman_command_string_st[43]; + goto compare; + } + break; + case 71: + if (len == 5) + { + resword = &gearman_command_string_st[44]; + goto compare; + } + break; } return 0; compare: @@ -597,5 +615,5 @@ } return 0; } -#line 109 "libgearman/command.gperf" +#line 111 "libgearman/command.gperf" --- libgearman/connection.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/connection.cc 2014-09-01 18:01:11.090690828 +0800 @@ -276,14 +276,14 @@ */ void gearman_connection_st::close_socket() { +#if defined(HAVE_SSL) && HAVE_SSL if (_ssl) { -#if defined(HAVE_SSL) && HAVE_SSL SSL_shutdown(_ssl); SSL_free(_ssl); _ssl= NULL; -#endif } +#endif if (fd != INVALID_SOCKET) { @@ -678,6 +678,8 @@ ERR_error_string_n(SSL_get_error(_ssl, 0), errorString, sizeof(errorString)); return gearman_error(universal, GEARMAN_COULD_NOT_CONNECT, errorString); } + + SSL_set_connect_state(_ssl); } #endif @@ -858,7 +860,13 @@ case SSL_ERROR_SSL: default: { - char errorString[80]; +# if defined(HAVE_OPENSSL) && HAVE_OPENSSL + if (ERR_peek_last_error()) + { + ssl_error= ERR_peek_last_error(); + } +# endif + char errorString[SSL_ERROR_SIZE]; ERR_error_string_n(ssl_error, errorString, sizeof(errorString)); close_socket(); return gearman_universal_set_error(universal, GEARMAN_LOST_CONNECTION, GEARMAN_AT, "SSL failure(%s)", errorString); @@ -1163,7 +1171,13 @@ case SSL_ERROR_SSL: default: { - char errorString[80]; +# if defined(HAVE_OPENSSL) && HAVE_OPENSSL + if (ERR_peek_last_error()) + { + ssl_error= ERR_peek_last_error(); + } +# endif + char errorString[SSL_ERROR_SIZE]; ERR_error_string_n(ssl_error, errorString, sizeof(errorString)); close_socket(); return gearman_universal_set_error(universal, GEARMAN_LOST_CONNECTION, GEARMAN_AT, "SSL failure(%s)", errorString); --- libgearman/execute.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/execute.cc 2014-08-02 20:27:11.055295057 +0800 @@ -68,6 +68,20 @@ return GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG; } +static inline gearman_command_t pick_command_by_priority_epoch(const gearman_job_priority_t &arg) +{ + if (arg == GEARMAN_JOB_PRIORITY_NORMAL) + { + return GEARMAN_COMMAND_SUBMIT_JOB_EPOCH; + } + else if (arg == GEARMAN_JOB_PRIORITY_HIGH) + { + return GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH; + } + + return GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH; +} + gearman_task_st *gearman_execute(gearman_client_st *client_shell, @@ -117,7 +131,7 @@ case GEARMAN_TASK_ATTR_EPOCH: task= add_task(*client, context, - GEARMAN_COMMAND_SUBMIT_JOB_EPOCH, + pick_command_by_priority_epoch(task_attr->priority), function, unique, arguments->value, --- libgearman/interface/universal.hpp 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/interface/universal.hpp 2014-09-01 18:03:03.997352617 +0800 @@ -38,6 +38,7 @@ #pragma once +#include #include "libgearman/allocator.hpp" #include "libgearman/server_options.hpp" #include "libgearman/interface/packet.hpp" @@ -68,12 +69,18 @@ bool non_blocking; bool no_new_data; bool _ssl; + struct gearman_vector_st *_ssl_ca_file; + struct gearman_vector_st *_ssl_certificate; + struct gearman_vector_st *_ssl_key; Options() : dont_track_packets(false), non_blocking(false), no_new_data(false), - _ssl(false) + _ssl(false), + _ssl_ca_file(NULL), + _ssl_certificate(NULL), + _ssl_key(NULL) { } } options; gearman_verbose_t verbose; @@ -208,6 +215,11 @@ const char* ssl_ca_file() const { + if (options._ssl_ca_file && options._ssl_ca_file->size()) + { + return options._ssl_ca_file->c_str(); + } + if (getenv("GEARMAND_CA_CERTIFICATE")) { return getenv("GEARMAND_CA_CERTIFICATE"); @@ -216,8 +228,27 @@ return GEARMAND_CA_CERTIFICATE; } + void ssl_ca_file(const char* ssl_ca_file_) + { + gearman_string_free(options._ssl_ca_file); + size_t ssl_ca_file_size_= 0; + if (ssl_ca_file_ && (ssl_ca_file_size_= strlen(ssl_ca_file_))) + { + options._ssl_ca_file= gearman_string_create(NULL, ssl_ca_file_, ssl_ca_file_size_); + } + else + { + options._ssl_ca_file= NULL; + } + } + const char* ssl_certificate() const { + if (options._ssl_certificate && options._ssl_certificate->size()) + { + return options._ssl_certificate->c_str(); + } + if (getenv("GEARMAN_CLIENT_PEM")) { return getenv("GEARMAN_CLIENT_PEM"); @@ -226,8 +257,27 @@ return GEARMAN_CLIENT_PEM; } + void ssl_certificate(const char *ssl_certificate_) + { + gearman_string_free(options._ssl_certificate); + size_t ssl_certificate_size_= 0; + if (ssl_certificate_ && (ssl_certificate_size_= strlen(ssl_certificate_))) + { + options._ssl_certificate= gearman_string_create(NULL, ssl_certificate_, ssl_certificate_size_); + } + else + { + options._ssl_certificate= NULL; + } + } + const char* ssl_key() const { + if (options._ssl_key && options._ssl_key->size()) + { + return options._ssl_key->c_str(); + } + if (getenv("GEARMAN_CLIENT_KEY")) { return getenv("GEARMAN_CLIENT_KEY"); @@ -236,6 +286,20 @@ return GEARMAN_CLIENT_KEY; } + void ssl_key(const char *ssl_key_) + { + gearman_string_free(options._ssl_key); + size_t ssl_key_size_= 0; + if (ssl_key_ && (ssl_key_size_= strlen(ssl_key_))) + { + options._ssl_key= gearman_string_create(NULL, ssl_key_, ssl_key_size_); + } + else + { + options._ssl_key= NULL; + } + } + private: bool init_ssl(); --- libgearman/protocol/submit.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/protocol/submit.cc 2014-08-02 19:43:57.085314194 +0800 @@ -113,6 +113,7 @@ gearman_return_t submit_epoch(gearman_universal_st& universal, gearman_packet_st& message, const gearman_unique_t& unique, + const gearman_command_t command, const gearman_string_t &function, const gearman_string_t &workload, time_t when) @@ -155,7 +156,7 @@ return gearman_packet_create_args(universal, message, GEARMAN_MAGIC_REQUEST, - GEARMAN_COMMAND_SUBMIT_JOB_EPOCH, + command, args, args_size, 4); } --- libgearman/protocol/submit.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/protocol/submit.h 2014-08-03 03:32:16.555202229 +0800 @@ -58,6 +58,7 @@ gearman_return_t submit_epoch(gearman_universal_st&, gearman_packet_st& message, const gearman_unique_t& unique, + const gearman_command_t command, const gearman_string_t &function, const gearman_string_t &workload, time_t when); --- libgearman/run.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/run.cc 2014-08-02 20:13:22.835301167 +0800 @@ -199,6 +199,8 @@ task->send.command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG || task->send.command == GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG || task->send.command == GEARMAN_COMMAND_SUBMIT_JOB_EPOCH || + task->send.command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH || + task->send.command == GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH || task->send.command == GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BACKGROUND) { task->error_code(GEARMAN_SUCCESS); --- libgearman/universal.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/universal.cc 2014-09-01 17:51:01.050717180 +0800 @@ -183,6 +183,15 @@ self.timeout= timeout; } +void gearman_universal_set_ssl(gearman_universal_st &self, bool ssl, + const char *ca_file, const char *certificate, const char *key_file) +{ + self.ssl(ssl); + self.ssl_ca_file(ca_file); + self.ssl_certificate(certificate); + self.ssl_key(key_file); +} + void gearman_set_log_fn(gearman_universal_st &self, gearman_log_fn *function, void *context, gearman_verbose_t verbose) { @@ -467,13 +476,34 @@ bool gearman_universal_st::init_ssl() { +#if defined(HAVE_SSL) && HAVE_SSL if (ssl()) { -#if defined(HAVE_SSL) && HAVE_SSL + // Check these files exist or not to avoid coredump. + FILE *file= NULL; + if ((file= fopen(ssl_ca_file(), "r")) == NULL) + { + gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to open CA certificate %s (%d: %s)", ssl_ca_file(), errno, strerror(errno)); + return false; + } + fclose(file); + if ((file= fopen(ssl_certificate(), "r")) == NULL) + { + gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to open certificate %s (%d: %s)", ssl_certificate(), errno, strerror(errno)); + return false; + } + fclose(file); + if ((file= fopen(ssl_key(), "r")) == NULL) + { + gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to open certificate key %s (%d: %s)", ssl_key(), errno, strerror(errno)); + return false; + } + fclose(file); + SSL_load_error_strings(); SSL_library_init(); - if ((_ctx_ssl= SSL_CTX_new(TLSv1_client_method())) == NULL) + if ((_ctx_ssl= SSL_CTX_new(SSLv23_client_method())) == NULL) { gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "CyaTLSv1_client_method() failed"); return false; @@ -496,8 +526,14 @@ gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to load certificate key %s", ssl_key()); return false; } -#endif // defined(HAVE_SSL) && HAVE_SSL + + if (SSL_CTX_check_private_key(_ctx_ssl) != SSL_SUCCESS) + { + gearman_universal_set_error(*this, GEARMAN_INVALID_ARGUMENT, GEARMAN_AT, "Failed to check private key"); + return false; + } } +#endif // defined(HAVE_SSL) && HAVE_SSL return true; } --- libgearman/universal.hpp 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/universal.hpp 2014-07-14 15:41:04.485239304 +0800 @@ -57,6 +57,9 @@ int gearman_universal_timeout(gearman_universal_st &self); +void gearman_universal_set_ssl(gearman_universal_st &self, bool ssl, + const char *ca_file, const char *certificate, const char *key_file); + void gearman_universal_set_namespace(gearman_universal_st &self, const char *namespace_key, size_t namespace_key_size); gearman_return_t cancel_job(gearman_universal_st& universal, --- libgearman/worker.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/worker.cc 2014-07-15 00:43:21.945244238 +0800 @@ -415,6 +415,15 @@ } } +void gearman_worker_set_ssl(gearman_worker_st *worker_shell, bool ssl, + const char *ca_file, const char *certificate, const char *key_file) +{ + if (worker_shell && worker_shell->impl()) + { + gearman_universal_set_ssl(worker_shell->impl()->universal, ssl, ca_file, certificate, key_file); + } +} + void *gearman_worker_context(const gearman_worker_st *worker) { if (worker and worker->impl()) --- libgearman/worker.hpp 2014-02-12 08:05:28.000000000 +0800 +++ libgearman/worker.hpp 2014-07-07 14:23:58.669334929 +0800 @@ -134,6 +134,7 @@ void enable_ssl() { + return; if (getenv("GEARMAND_CA_CERTIFICATE")) { gearman_worker_add_options(_worker, GEARMAN_WORKER_SSL); --- libgearman-1.0/client.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-1.0/client.h 2014-08-06 11:04:56.002013287 +0800 @@ -172,6 +172,13 @@ void gearman_client_set_timeout(gearman_client_st *client, int timeout); /** + * See gearman_universal_set_ssl() for details. + */ +GEARMAN_API +void gearman_client_set_ssl(gearman_client_st *client, bool ssl, + const char *ca_file, const char *certificate, const char *key_file); + +/** * Get the application context for a client. * * @param[in] client Structure previously initialized with @@ -397,7 +404,56 @@ gearman_job_handle_t job_handle); /** - * Get the status for a backgound job. + * Run a task in the future. + * + * @param[in] client Structure previously initialized with + * gearman_client_create() or gearman_client_clone(). + * @param[in] function_name The name of the function to run. + * @param[in] unique Optional unique job identifier, or NULL for a new UUID. + * @param[in] workload The workload to pass to the function when it is run. + * @param[in] workload_size Size of the workload. + * @param[in] when The Time when to run. + * @param[out] job_handle A buffer to store the job handle in. Must be at least + GEARMAN_JOB_HANDLE_SIZE bytes long. + * @return Standard gearman return value. + */ +GEARMAN_API +gearman_return_t gearman_client_do_epoch(gearman_client_st *client, + const char *function_name, + const char *unique, + const void *workload, + size_t workload_size, + time_t when, + gearman_job_handle_t job_handle); + +/** + * Run a high priority task in the future. See + * gearman_client_do_epoch() for parameter and return information. + */ +GEARMAN_API +gearman_return_t gearman_client_do_high_epoch(gearman_client_st *client, + const char *function_name, + const char *unique, + const void *workload, + size_t workload_size, + time_t when, + gearman_job_handle_t job_handle); + +/** + * Run a low priority task in the future. See + * gearman_client_do_epoch() for parameter and return information. + */ +GEARMAN_API +gearman_return_t gearman_client_do_low_epoch(gearman_client_st *client, + const char *function_name, + const char *unique, + const void *workload, + size_t workload_size, + time_t when, + gearman_job_handle_t job_handle); + +/** + * Get the status for a backgound or future job. * * @param[in] client Structure previously initialized with * gearman_client_create() or gearman_client_clone(). @@ -570,6 +626,54 @@ gearman_return_t *ret_ptr); /** + * Add an epoch task to be run in parallel. See + * gearman_client_add_task() for details. + * @param[in] when The time when to run. + */ +GEARMAN_API +gearman_task_st *gearman_client_add_task_epoch(gearman_client_st *client, + gearman_task_st *task, + void *context, + const char *function_name, + const char *unique, + const void *workload, + size_t workload_size, + time_t when, + gearman_return_t *ret_ptr); + +/** + * Add an epoch task to be run in parallel. See + * gearman_client_add_task() for details. + * @param[in] when The time when to run. + */ +GEARMAN_API +gearman_task_st *gearman_client_add_task_high_epoch(gearman_client_st *client, + gearman_task_st *task, + void *context, + const char *function_name, + const char *unique, + const void *workload, + size_t workload_size, + time_t when, + gearman_return_t *ret_ptr); + +/** + * Add an epoch task to be run in parallel. See + * gearman_client_add_task() for details. + * @param[in] when The time when to run. + */ +GEARMAN_API +gearman_task_st *gearman_client_add_task_low_epoch(gearman_client_st *client, + gearman_task_st *task, + void *context, + const char *function_name, + const char *unique, + const void *workload, + size_t workload_size, + time_t when, + gearman_return_t *ret_ptr); + +/** * Add task to get the status for a backgound task in parallel. * * @param[in] client Structure previously initialized with --- libgearman-1.0/protocol.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-1.0/protocol.h 2014-08-02 19:19:49.235324876 +0800 @@ -87,6 +87,8 @@ GEARMAN_COMMAND_JOB_ASSIGN_ALL, /* J->W: HANDLE[0]FUNC[0]UNIQ[0]REDUCER[0]ARGS */ GEARMAN_COMMAND_GET_STATUS_UNIQUE, /* C->J: UNIQUE */ GEARMAN_COMMAND_STATUS_RES_UNIQUE, /* J->C: UNIQUE[0]KNOWN[0]RUNNING[0]NUM[0]DENOM[0]CLIENT_COUNT */ + GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH, + GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH, GEARMAN_COMMAND_MAX /* Always add new commands before this. */ }; --- libgearman-1.0/worker.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-1.0/worker.h 2014-07-15 00:41:40.291909980 +0800 @@ -180,6 +180,13 @@ void gearman_worker_set_timeout(gearman_worker_st *worker, int timeout); /** + * See gearman_universal_set_ssl() for details. + */ +GEARMAN_API +void gearman_worker_set_ssl(gearman_worker_st *worker, bool ssl, + const char *ca_file, const char *certificate, const char *key_file); + +/** * Get the application context for a worker. * * @param[in] worker Structure previously initialized with --- libgearman-server/connection.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/connection.cc 2014-09-02 00:22:03.191318482 +0800 @@ -145,6 +145,9 @@ con->client_list= NULL; con->_host= dcon->host; con->_port= dcon->port; + con->_function_names= NULL; + con->_function_names_size= 0; + con->_function_names_count= 0; strcpy(con->id, "-"); con->timeout_event= NULL; @@ -180,15 +183,12 @@ void gearman_server_con_attempt_free(gearman_server_con_st *con) { - con->_host= NULL; - con->_port= NULL; - + con->is_dead= true; if (Server->flags.threaded) { if (!(con->proc_removed) and !(Server->proc_shutdown)) { gearman_server_con_delete_timeout(con); - con->is_dead= true; con->is_sleeping= false; con->is_exceptions= Gearmand()->_exceptions; con->is_noop_sent= false; @@ -204,8 +204,6 @@ void gearman_server_con_free(gearman_server_con_st *con) { gearman_server_thread_st *thread= con->thread; - con->_host= NULL; - con->_port= NULL; // Correct location? #if defined(HAVE_SSL) && HAVE_SSL @@ -294,6 +292,9 @@ } assert(lock_error == 0); + con->_host= NULL; + con->_port= NULL; + if (thread->free_con_count < GEARMAND_MAX_FREE_SERVER_CON) { GEARMAND_LIST__ADD(thread->free_con, con); @@ -375,8 +376,37 @@ { while (con->worker_list != NULL) { + if (con->is_dead == true) + { + uint32_t comma= (con->_function_names_size == 0) ? 0 : 1; + gearman_server_function_st *function= con->worker_list->function; + char *_function_names= (char *)realloc(con->_function_names, con->_function_names_size +comma +function->function_name_size +1); + if (_function_names != NULL) + { + con->_function_names= _function_names; + if (comma == 1) + { + con->_function_names[con->_function_names_size]= ','; + } + memcpy(con->_function_names +con->_function_names_size +comma, function->function_name, function->function_name_size +1); + con->_function_names_size += comma +function->function_name_size; + con->_function_names_count++; + } + else + { + gearmand_merror("realloc", char, con->_function_names_size +comma +function->function_name_size +1); + } + } gearman_server_worker_free(con->worker_list); } + if (con->is_dead == true && con->_function_names != NULL && con->_function_names_size != 0) + { + gearman_server_notify_worker_failed(Server, con); + free(con->_function_names); + con->_function_names= NULL; + con->_function_names_size= 0; + con->_function_names_count= 0; + } } void gearman_server_con_to_be_freed_add(gearman_server_con_st *con) --- libgearman-server/constants.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/constants.h 2014-08-28 10:32:50.478525883 +0800 @@ -77,6 +77,7 @@ #define GEARMAND_MAX_FREE_SERVER_PACKET 2000 #define GEARMAND_MAX_FREE_SERVER_WORKER 1000 #define GEARMAND_OPTION_SIZE 64 +#define GEARMAND_ACTION_SIZE 256 #define GEARMAND_PACKET_HEADER_SIZE 12 #define GEARMAND_PIPE_BUFFER_SIZE 256 #define GEARMAND_RECV_BUFFER_SIZE 8192 --- libgearman-server/error/strerror.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/error/strerror.cc 2014-08-26 12:00:51.904967603 +0800 @@ -147,6 +147,10 @@ return "The argument was too large for Gearman to handle."; case GEARMAND_INVALID_ARGUMENT: return "An invalid argument was passed to a function."; + case GEARMAND_JOB_NOT_CANCELED: + return "JOB_NOT_CANCELED"; + case GEARMAND_JOB_CANCELED: + return "JOB_CANCELED"; case GEARMAND_MAX_RETURN: default: return "Gibberish returned!"; --- libgearman-server/error/type.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/error/type.h 2014-08-26 11:45:54.878339685 +0800 @@ -93,6 +93,8 @@ GEARMAND_TIMEOUT, GEARMAND_ARGUMENT_TOO_LARGE, GEARMAND_INVALID_ARGUMENT, + GEARMAND_JOB_NOT_CANCELED, + GEARMAND_JOB_CANCELED, GEARMAND_MAX_RETURN /* Always add new error code before */ }; --- libgearman-server/function.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/function.cc 2014-09-02 00:05:47.748027286 +0800 @@ -46,6 +46,7 @@ #include #include +#include /* * Public definitions @@ -80,19 +81,12 @@ uint32_t function_key) { gearman_server_function_st* function= new (std::nothrow) gearman_server_function_st; - if (function == NULL) { gearmand_merror("new gearman_server_function_st", gearman_server_function_st, 0); return NULL; } - function->worker_count= 0; - function->job_count= 0; - function->job_total= 0; - function->job_running= 0; - memset(function->max_queue_size, GEARMAND_DEFAULT_MAX_QUEUE_SIZE, sizeof(uint32_t) * GEARMAN_JOB_PRIORITY_MAX); - function->function_name= new char[function_name_size +1]; if (function->function_name == NULL) { @@ -104,19 +98,41 @@ memcpy(function->function_name, function_name, function_name_size); function->function_name[function_name_size]= 0; function->function_name_size= function_name_size; + + function->job_count= 0; + function->job_total= 0; + function->job_running= 0; + function->worker_count= 0; function->worker_list= NULL; - memset(function->job_list, 0, - sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); - memset(function->job_end, 0, - sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); + + memset(function->job_epoch_list, 0, sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); + memset(function->job_epoch_end, 0, sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); + memset(function->job_bg_list, 0, sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); + memset(function->job_bg_end, 0, sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); + memset(function->job_list, 0, sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); + memset(function->job_end, 0, sizeof(gearman_server_job_st *) * GEARMAN_JOB_PRIORITY_MAX); + memset(function->job_totals, 0, sizeof(uint32_t) * GEARMAN_JOB_PRIORITY_MAX); + + memset(&(function->options), 0, sizeof(struct Options_st)); + function->job_count_max_timer= NULL; + function->worker_count_min_timer= NULL; + if (server->options.job_count_max != 0 and server->options.job_count_max_interval != 0) + { + gearman_server_timer_job_count_max(server, function); + } + if (server->options.worker_count_min != 0 and server->options.worker_count_min_interval != 0) + { + gearman_server_timer_worker_count_min(server, function); + } + GEARMAND_HASH__ADD(server->function, function_key, function); return function; } -gearman_server_function_st * -gearman_server_function_get(gearman_server_st *server, - const char *function_name, - size_t function_name_size) +gearman_server_function_st *gearman_server_function_get(gearman_server_st *server, + const char *function_name, + size_t function_name_size, + bool auto_create) { gearman_server_function_st *function; @@ -131,6 +147,11 @@ } } + if (auto_create == false) + { + return NULL; + } + return gearman_server_function_create(server, function_name, function_name_size, function_hash); } @@ -140,7 +161,278 @@ function_key= _server_function_hash(function->function_name, function->function_name_size); function_key= function_key % GEARMAND_DEFAULT_HASH_SIZE; GEARMAND_HASH__DEL(server->function, function_key, function); + timer_delete(function->job_count_max_timer); + timer_delete(function->worker_count_min_timer); delete [] function->function_name; delete function; } #pragma GCC diagnostic pop + + +void gearman_server_notify_job_retries(gearman_server_st *server, gearman_server_job_st *job) +{ + if (server->job_retries_action[0] == '\0') + { + return; + } + + char _job_retries[11]; + sprintf(_job_retries, "%u", job->retries); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[6]; + argv[0]= server->job_retries_action; + argv[1]= job->unique; + argv[2]= job->job_handle; + argv[3]= job->function->function_name; + argv[4]= _job_retries; + argv[5]= 0; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4]); + execv(server->job_retries_action, argv); + gearmand_log_warning(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s %s (%d)%s", argv[0], argv[1], argv[2], argv[3], argv[4], errno, strerror(errno)); + exit(0); + } + else + { + return; + } +} + +void gearman_server_notify_job_retries_warn(gearman_server_st *server, gearman_server_job_st *job) +{ + if (server->job_retries_warn_action[0] == '\0') + { + return; + } + + char _job_retries[11]; + sprintf(_job_retries, "%u", job->retries); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[6]; + argv[0]= server->job_retries_warn_action; + argv[1]= job->unique; + argv[2]= job->job_handle; + argv[3]= job->function->function_name; + argv[4]= _job_retries; + argv[5]= 0; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4]); + execv(server->job_retries_warn_action, argv); + gearmand_log_warning(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s %s (%d)%s", argv[0], argv[1], argv[2], argv[3], argv[4], errno, strerror(errno)); + exit(0); + } + else + { + return; + } +} + +void gearman_server_notify_job_count_max(gearman_server_st *server, gearman_server_function_st *function) +{ + uint32_t job_count_max= (function->options.job_count_max == 0) ? server->options.job_count_max : function->options.job_count_max; + if (job_count_max == 0 || job_count_max >= function->job_count || server->job_count_max_action[0] == '\0') + { + return; + } + + char _job_count[11]; + char _job_count_max[11]; + sprintf(_job_count_max, "%u", job_count_max); + sprintf(_job_count, "%u", function->job_count); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[5]; + argv[0]= server->job_count_max_action; + argv[1]= function->function_name; + argv[2]= _job_count_max; + argv[3]= _job_count; + argv[4]= 0; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]); + execv(server->job_count_max_action, argv); + gearmand_log_warning(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s (%d)%s", argv[0], argv[1], argv[2], argv[3], errno, strerror(errno)); + exit(0); + } + else + { + return; + } +} + +void gearman_server_notify_worker_count_min(gearman_server_st *server, gearman_server_function_st *function) +{ + uint32_t worker_count_min= (function->options.worker_count_min == 0) ? server->options.worker_count_min : function->options.worker_count_min; + if (worker_count_min == 0 || worker_count_min <= function->worker_count || server->worker_count_min_action[0] == '\0') + { + return; + } + + char _worker_count[11]; + char _worker_count_min[11]; + sprintf(_worker_count_min, "%u", worker_count_min); + sprintf(_worker_count, "%u", function->worker_count); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[5]; + argv[0]= server->worker_count_min_action; + argv[1]= function->function_name; + argv[2]= _worker_count_min; + argv[3]= _worker_count; + argv[4]= 0; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]); + execv(server->worker_count_min_action, argv); + gearmand_log_warning(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s (%d)%s", argv[0], argv[1], argv[2], argv[3], errno, strerror(errno)); + exit(0); + } + else + { + return; + } +} + +void gearman_server_notify_worker_failed(gearman_server_st *server, gearman_server_con_st *con) +{ + if (server->worker_failed_action[0] == '\0') + { + return; + } + + char _function_names_count[11]; + sprintf(_function_names_count, "%u", con->_function_names_count); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[6]; + argv[0]= server->worker_failed_action; + argv[1]= (char *)con->_host; + argv[2]= (char *)con->_port; + argv[3]= _function_names_count; + argv[4]= con->_function_names; + argv[5]= 0; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4]); + execv(server->worker_failed_action, argv); + gearmand_log_warning(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s %s (%d)%s", argv[0], argv[1], argv[2], argv[3], argv[4], errno, strerror(errno)); + exit(0); + } + else + { + return; + } +} + +static void _gearman_server_notify_job_count_max(sigval_t sigval) +{ + gearman_server_function_st *function= (gearman_server_function_st *)(sigval.sival_ptr); + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer notify for (%.*s, job_count_max)", function->function_name_size, function->function_name); + gearman_server_notify_job_count_max(Server, function); +} + +static void _gearman_server_notify_worker_count_min(sigval_t sigval) +{ + gearman_server_function_st *function= (gearman_server_function_st *)(sigval.sival_ptr); + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer notify for (%.*s, worker_count_min)", function->function_name_size, function->function_name); + gearman_server_notify_worker_count_min(Server, function); +} + +static bool _gearman_server_timer(gearman_server_function_st *function, timer_t &timerid, const char *type, uint32_t count, uint32_t interval, const char *action, void (*notify)(sigval_t)) +{ + if (count == 0 || interval == 0 || action[0] == '\0') + { + if (timerid != NULL) + { + timer_delete(timerid); + timerid= NULL; + } + } + else if (timerid == NULL) + { + struct sigevent sigev; + memset(&sigev, 0, sizeof(struct sigevent)); + sigev.sigev_value.sival_ptr= (void *)function; + sigev.sigev_notify= SIGEV_THREAD; + sigev.sigev_notify_function= notify; + if (timer_create(CLOCK_REALTIME, &sigev, &timerid) != 0) + { + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "timer_create for (%.*s, %s, %u, %u) error (%d)%s", + function->function_name_size, function->function_name, type, + count, interval, errno, strerror(errno)); + timer_delete(timerid); + timerid= NULL; + return false; + } + + struct itimerspec itimer; + memset(&itimer, 0, sizeof(struct itimerspec)); + itimer.it_value.tv_sec= interval; + itimer.it_interval.tv_sec= interval; + if (timer_settime(timerid, 0, &itimer, NULL) != 0) + { + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "timer_settime for (%.*s, %s, %u, %u) error (%d)%s", + function->function_name_size, function->function_name, type, + count, interval, errno, strerror(errno)); + timer_delete(timerid); + timerid= NULL; + return false; + } + } + else + { + struct itimerspec itimer; + if (timer_gettime(timerid, &itimer) != 0) + { + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "timer_gettime for (%.*s, %s, %u, %u) error (%d)%s", + function->function_name_size, function->function_name, type, + count, interval, errno, strerror(errno)); + return false; + } + if (itimer.it_interval.tv_sec == interval) + { + return true; + } + + itimer.it_value.tv_sec+= (interval -itimer.it_interval.tv_sec); + itimer.it_interval.tv_sec= interval; + if (itimer.it_value.tv_sec < 0 || (itimer.it_value.tv_sec == 0 && itimer.it_value.tv_nsec <= 0)) + { + itimer.it_value.tv_sec= 0; + itimer.it_value.tv_nsec= 1000000; + } + if (timer_settime(timerid, 0, &itimer, NULL) != 0) + { + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "timer_settime for (%.*s, %s, %u, %u) error (%d)%s", + function->function_name_size, function->function_name, type, + count, interval, errno, strerror(errno)); + return false; + } + } + return true; +} + +bool gearman_server_timer_job_count_max(gearman_server_st *server, gearman_server_function_st *function) +{ + uint32_t job_count_max= (function->options.job_count_max == 0) ? server->options.job_count_max : function->options.job_count_max; + uint32_t job_count_max_interval= (function->options.job_count_max_interval == 0) ? server->options.job_count_max_interval : function->options.job_count_max_interval; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer config for (%.*s, job_count_max, %u, %u)", function->function_name_size, function->function_name, job_count_max, job_count_max_interval); + return _gearman_server_timer(function, function->job_count_max_timer, "job_count_max", job_count_max, job_count_max_interval, server->job_count_max_action, _gearman_server_notify_job_count_max); +} + +bool gearman_server_timer_worker_count_min(gearman_server_st *server, gearman_server_function_st *function) +{ + uint32_t worker_count_min= (function->options.worker_count_min == 0) ? server->options.worker_count_min : function->options.worker_count_min; + uint32_t worker_count_min_interval= (function->options.worker_count_min_interval == 0) ? server->options.worker_count_min_interval : function->options.worker_count_min_interval; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer config for (%.*s, worker_count_min, %u, %u)", function->function_name_size, function->function_name, worker_count_min, worker_count_min_interval); + return _gearman_server_timer(function, function->worker_count_min_timer, "worker_count_min", worker_count_min, worker_count_min_interval, server->worker_count_min_action, _gearman_server_notify_worker_count_min); +} --- libgearman-server/function.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/function.h 2014-09-01 10:17:06.131893661 +0800 @@ -63,9 +63,10 @@ Add a new function to a server instance. */ GEARMAN_API - gearman_server_function_st * gearman_server_function_get(gearman_server_st *server, - const char *function_name, - size_t function_name_size); +gearman_server_function_st * gearman_server_function_get(gearman_server_st *server, + const char *function_name, + size_t function_name_size, + bool auto_create= true); /** * Free a server function structure. @@ -73,6 +74,48 @@ GEARMAN_API void gearman_server_function_free(gearman_server_st *server, gearman_server_function_st *function); +/** + * Notify job->retries reaches job_retries + */ +GEARMAN_API +void gearman_server_notify_job_retries(gearman_server_st *server, gearman_server_job_st *job); + +/** + * Notify job->retries reaches job_retries_warn + */ +GEARMAN_API +void gearman_server_notify_job_retries_warn(gearman_server_st *server, gearman_server_job_st *job); + +/** + * Notify job_count more than job_count_max + */ +GEARMAN_API +void gearman_server_notify_job_count_max(gearman_server_st *server, gearman_server_function_st *function); + +/** + * Notify worker_count less than worker_count_min + */ +GEARMAN_API +void gearman_server_notify_worker_count_min(gearman_server_st *server, gearman_server_function_st *function); + +/** + * Notify worker_failed + */ +GEARMAN_API +void gearman_server_notify_worker_failed(gearman_server_st *server, gearman_server_con_st *con); + +/** + * Creat / Set timer for job_count_max + */ +GEARMAN_API +bool gearman_server_timer_job_count_max(gearman_server_st *server, gearman_server_function_st *function); + +/** + * Creat / Set timer for worker_count_min + */ +GEARMAN_API +bool gearman_server_timer_worker_count_min(gearman_server_st *server, gearman_server_function_st *function); + /** @} */ #ifdef __cplusplus --- libgearman-server/gearmand.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/gearmand.cc 2014-08-29 23:59:06.178299844 +0800 @@ -114,11 +114,15 @@ static void _close_events(gearmand_st *gearmand); static bool gearman_server_create(gearman_server_st& server, - const uint32_t job_retries, const char *job_handle_prefix, - uint8_t worker_wakeup, bool round_robin, - uint32_t hashtable_buckets); + uint32_t hashtable_buckets, + struct Options_st &options, + const char *job_retries_action, + const char *job_retries_warn_action, + const char *job_count_max_action, + const char *worker_count_min_action, + const char *worker_failed_action); static void gearmand_set_log_fn(gearmand_st *gearmand, gearmand_log_fn *function, void *context, const gearmand_verbose_t verbose); @@ -175,6 +179,13 @@ delete worker; } + gearman_server_epoch_job_st *epoch_job= NULL; + while ((epoch_job= server.epoch_job_list) != NULL) + { + server.epoch_job_list= epoch_job->next; + gearman_server_epoch_job_free(epoch_job); + } + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "removing queue: %s", (server.queue_version == QUEUE_VERSION_CLASS) ? "CLASS" : "FUNCTION"); if (server.queue_version == QUEUE_VERSION_CLASS) { @@ -224,13 +235,17 @@ const char *host_arg, uint32_t threads_arg, int backlog_arg, - const uint32_t job_retries, const char *job_handle_prefix, - uint8_t worker_wakeup, gearmand_log_fn *log_function, void *log_context, const gearmand_verbose_t verbose_arg, bool round_robin, bool exceptions_, - uint32_t hashtable_buckets) + uint32_t hashtable_buckets, + struct Options_st &options, + const char *job_retries_action, + const char *job_retries_warn_action, + const char *job_count_max_action, + const char *worker_count_min_action, + const char *worker_failed_action) { assert(_global_gearmand == NULL); if (_global_gearmand) @@ -249,9 +264,9 @@ gearmand->socketopt()= config->config.sockopt(); - if (gearman_server_create(gearmand->server, job_retries, - job_handle_prefix, worker_wakeup, - round_robin, hashtable_buckets) == false) + if (gearman_server_create(gearmand->server, job_handle_prefix, round_robin, hashtable_buckets, options, + job_retries_action, job_retries_warn_action, job_count_max_action, + worker_count_min_action, worker_failed_action) == false) { delete gearmand; _global_gearmand= NULL; @@ -1195,21 +1210,24 @@ } static bool gearman_server_create(gearman_server_st& server, - const uint32_t job_retries_arg, const char *job_handle_prefix, - uint8_t worker_wakeup_arg, bool round_robin_arg, - uint32_t hashtable_buckets) + uint32_t hashtable_buckets, + struct Options_st &options, + const char *job_retries_action, + const char *job_retries_warn_action, + const char *job_count_max_action, + const char *worker_count_min_action, + const char *worker_failed_action) { server.state.queue_startup= false; + server.state.epoch_startup= false; server.flags.round_robin= round_robin_arg; server.flags.threaded= false; server.shutdown= false; server.shutdown_graceful= false; server.proc_wakeup= false; server.proc_shutdown= false; - server.job_retries= job_retries_arg; - server.worker_wakeup= worker_wakeup_arg; server.thread_count= 0; server.free_packet_count= 0; server.function_count= 0; @@ -1223,6 +1241,7 @@ server.free_job_list= NULL; server.free_client_list= NULL; server.free_worker_list= NULL; + server.epoch_job_list= NULL; server.queue_version= QUEUE_VERSION_NONE; server.queue.object= NULL; @@ -1275,6 +1294,88 @@ return false; } + memcpy(&server.options, &options, sizeof(struct Options_st)); + + if (job_retries_action != NULL) + { + checked_length= snprintf(server.job_retries_action, GEARMAND_ACTION_SIZE, "%s", job_retries_action); + if (checked_length >= GEARMAND_ACTION_SIZE || checked_length < 0) + { + gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "Available length %d not enough to store job_retries_action %s", + GEARMAND_ACTION_SIZE, server.job_retries_action); + gearman_server_free(server); + return false; + } + } + else + { + server.job_retries_action[0]= '\0'; + } + + if (job_retries_warn_action != NULL) + { + checked_length= snprintf(server.job_retries_warn_action, GEARMAND_ACTION_SIZE, "%s", job_retries_warn_action); + if (checked_length >= GEARMAND_ACTION_SIZE || checked_length < 0) + { + gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "Available length %d not enough to store job_retries_warn_action %s", + GEARMAND_ACTION_SIZE, server.job_retries_warn_action); + gearman_server_free(server); + return false; + } + } + else + { + server.job_retries_warn_action[0]= '\0'; + } + + if (job_count_max_action != NULL) + { + checked_length= snprintf(server.job_count_max_action, GEARMAND_ACTION_SIZE, "%s", job_count_max_action); + if (checked_length >= GEARMAND_ACTION_SIZE || checked_length < 0) + { + gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "Available length %d not enough to store job_count_max_action %s", + GEARMAND_ACTION_SIZE, server.job_count_max_action); + gearman_server_free(server); + return false; + } + } + else + { + server.job_count_max_action[0]= '\0'; + } + + if (worker_count_min_action != NULL) + { + checked_length= snprintf(server.worker_count_min_action, GEARMAND_ACTION_SIZE, "%s", worker_count_min_action); + if (checked_length >= GEARMAND_ACTION_SIZE || checked_length < 0) + { + gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "Available length %d not enough to store worker_count_min_action %s", + GEARMAND_ACTION_SIZE, server.worker_count_min_action); + gearman_server_free(server); + return false; + } + } + else + { + server.worker_count_min_action[0]= '\0'; + } + + if (worker_failed_action != NULL) + { + checked_length= snprintf(server.worker_failed_action, GEARMAND_ACTION_SIZE, "%s", worker_failed_action); + if (checked_length >= GEARMAND_ACTION_SIZE || checked_length < 0) + { + gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "Available length %d not enough to store worker_failed_action %s", + GEARMAND_ACTION_SIZE, server.worker_failed_action); + gearman_server_free(server); + return false; + } + } + else + { + server.worker_failed_action[0]= '\0'; + } + server.job_handle_count= 1; return true; --- libgearman-server/gearmand_con.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/gearmand_con.cc 2014-08-26 11:47:12.411669669 +0800 @@ -210,8 +210,8 @@ bool(server_job->unique[0]) ? server_job->unique : "", uint32_t(strlen(server_job->unique)), unique, uint32_t(unique_length)); - if (bool(server_job->unique[0]) and - (strcmp(server_job->unique, unique) == 0)) + if (server_job->unique_key == key and server_job->unique_length == unique_length + and strncmp(server_job->unique, unique, unique_length) == 0) { /* Check to make sure the worker asking for the job still owns the job. */ if (worker_con != NULL and @@ -237,8 +237,8 @@ for (gearman_server_job_st *server_job= server->job_hash[key % server->hashtable_buckets]; server_job != NULL; server_job= server_job->next) { - if (server_job->job_handle_key == key and - strncmp(server_job->job_handle, job_handle, GEARMAND_JOB_HANDLE_SIZE) == 0) + if (server_job->job_handle_key == key and strlen(server_job->job_handle) == job_handle_length + and strncmp(server_job->job_handle, job_handle, job_handle_length) == 0) { /* Check to make sure the worker asking for the job still owns the job. */ if (worker_con != NULL and @@ -254,59 +254,152 @@ return NULL; } +gearmand_error_t _gearman_server_job_cancel(gearman_server_job_st *server_job) +{ + if (server_job == NULL) + { + return GEARMAND_NO_JOBS; + } + else if (server_job->ignore_job == true) + { + return GEARMAND_JOB_CANCELED; + } + + /* Queue the fail packet for all clients. */ + for (gearman_server_client_st* client= server_job->client_list; client != NULL; client= client->job_next) + { + gearmand_error_t ret= gearman_server_io_packet_add(client->con, false, + GEARMAN_MAGIC_RESPONSE, + GEARMAN_COMMAND_WORK_FAIL, + server_job->job_handle, + (size_t)strlen(server_job->job_handle), + NULL); + if (gearmand_failed(ret)) + { + gearmand_log_gerror_warn(GEARMAN_DEFAULT_LOG_PARAM, ret, "Failed to send WORK_FAIL packet to %s:%s", client->con->host(), client->con->port()); + } + } + + /* Remove from persistent queue if one exists. */ + if (server_job->job_queued) + { + gearmand_error_t ret= gearman_queue_done(Server, + server_job->unique, + server_job->unique_length, + server_job->function->function_name, + server_job->function->function_name_size); + if (gearmand_failed(ret)) + { + return gearmand_gerror("Remove from persistent queue", ret); + } + } + + server_job->ignore_job= true; + return GEARMAND_SUCCESS; +} + +gearmand_error_t gearman_server_job_cancel_by_unique(gearman_server_st& server, + const char *unique, + const size_t unique_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "cancel: %.*s", unique_length, unique); + return _gearman_server_job_cancel(gearman_server_job_get_by_unique(&server, unique, unique_length, NULL)); +} + gearmand_error_t gearman_server_job_cancel(gearman_server_st& server, const char *job_handle, const size_t job_handle_length) { - gearmand_error_t ret= GEARMAND_NO_JOBS; - uint32_t key= _server_job_hash(job_handle, job_handle_length); + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "cancel: %.*s", job_handle_length, job_handle); + return _gearman_server_job_cancel(gearman_server_job_get(&server, job_handle, job_handle_length, NULL)); +} - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "cancel: %.*s", int(job_handle_length), job_handle); +gearmand_error_t _gearman_server_job_clean(gearman_server_job_st *server_job) +{ + if (server_job == NULL) + { + return GEARMAND_NO_JOBS; + } + else if (server_job->ignore_job == false) + { + return GEARMAND_JOB_NOT_CANCELED; + } - for (gearman_server_job_st *server_job= server.job_hash[key % server.hashtable_buckets]; - server_job != NULL; - server_job= server_job->next) + if (server_job->function_next != NULL) { - if (server_job->job_handle_key == key and - strncmp(server_job->job_handle, job_handle, GEARMAND_JOB_HANDLE_SIZE) == 0) - { - /* Queue the fail packet for all clients. */ - for (gearman_server_client_st* client= server_job->client_list; client != NULL; client= client->job_next) - { - ret= gearman_server_io_packet_add(client->con, false, - GEARMAN_MAGIC_RESPONSE, - GEARMAN_COMMAND_WORK_FAIL, - server_job->job_handle, - (size_t)strlen(server_job->job_handle), - NULL); - if (gearmand_failed(ret)) - { - gearmand_log_gerror_warn(GEARMAN_DEFAULT_LOG_PARAM, ret, "Failed to send WORK_FAIL packet to %s:%s", client->con->host(), client->con->port()); - } - } + server_job->function_next->function_prev= server_job->function_prev; + } + if (server_job->function_prev != NULL) + { + server_job->function_prev->function_next= server_job->function_next; + } - /* Remove from persistent queue if one exists. */ - if (server_job->job_queued) - { - ret= gearman_queue_done(Server, - server_job->unique, - server_job->unique_length, - server_job->function->function_name, - server_job->function->function_name_size); - if (gearmand_failed(ret)) - { - return gearmand_gerror("Remove from persistent queue", ret); - } - } + gearman_server_job_free(server_job); + + return GEARMAND_SUCCESS; +} + +gearmand_error_t gearman_server_job_clean_by_unique(gearman_server_st &server, + const char *unique, + const size_t unique_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "clean: %.*s", unique_length, unique); + return _gearman_server_job_clean(gearman_server_job_get_by_unique(&server, unique, unique_length, NULL)); +} - server_job->ignore_job= true; - server_job->job_queued= false; +gearmand_error_t gearman_server_job_clean(gearman_server_st &server, + const char *job_handle, + const size_t job_handle_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "clean: %.*s", job_handle_length, job_handle); + return _gearman_server_job_clean(gearman_server_job_get(&server, job_handle, job_handle_length, NULL)); +} - return GEARMAND_SUCCESS; +gearmand_error_t _gearman_server_job_restore(gearman_server_job_st *server_job) +{ + if (server_job == NULL) + { + return GEARMAND_NO_JOBS; + } + else if (server_job->ignore_job == false) + { + return GEARMAND_JOB_NOT_CANCELED; + } + + /* Add into persistent queue if one used to exist. */ + if (server_job->job_queued) + { + gearmand_error_t ret= gearman_queue_add(Server, + server_job->unique, + server_job->unique_length, + server_job->function->function_name, + server_job->function->function_name_size, + server_job->data, server_job->data_size, + server_job->priority, server_job->when); + if (gearmand_failed(ret)) + { + return gearmand_gerror("Add into persistent queue", ret); } } - return ret; + server_job->ignore_job= false; + return GEARMAND_SUCCESS; +} + +gearmand_error_t gearman_server_job_restore_by_unique(gearman_server_st &server, + const char *unique, + const size_t unique_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "restore: %.*s", unique_length, unique); + return _gearman_server_job_restore(gearman_server_job_get_by_unique(&server, unique, unique_length, NULL)); +} + +gearmand_error_t gearman_server_job_restore(gearman_server_st &server, + const char *job_handle, + const size_t job_handle_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "restore: %.*s", job_handle_length, job_handle); + return _gearman_server_job_restore(gearman_server_job_get(&server, job_handle, job_handle_length, NULL)); } gearman_server_job_st * gearman_server_job_peek(gearman_server_con_st *server_con) @@ -315,35 +408,38 @@ server_worker != NULL; server_worker= server_worker->con_next) { - if (server_worker->function->job_count != 0) + if (server_worker->function != NULL and server_worker->function->job_count != 0) { for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority != GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) { - gearman_server_job_st *server_job; - server_job= server_worker->function->job_list[priority]; - - int64_t current_time= (int64_t)time(NULL); - - while(server_job && - server_job->when != 0 && - server_job->when > current_time) + gearman_server_job_st *server_job= NULL; + if (server_job == NULL) { - server_job= server_job->function_next; + server_job= server_worker->function->job_epoch_list[priority]; + if (server_job != NULL and server_job->when > time(NULL)) + { + server_job= NULL; + } } - - if (server_job != NULL) + if (server_job == NULL) + { + server_job= server_worker->function->job_list[priority]; + } + if (server_job == NULL) { + server_job= server_worker->function->job_bg_list[priority]; + } + if (server_job != NULL) + { if (server_job->ignore_job) { /* This is only happens when a client disconnects from a foreground job. We do this because we don't want to run the job anymore. */ - server_job->ignore_job= false; - - gearman_server_job_free(gearman_server_job_take(server_con)); - + server_job->function->job_count--; + gearman_server_job_free(server_job); return gearman_server_job_peek(server_con); } @@ -352,16 +448,15 @@ } } } - return NULL; } gearman_server_job_st *gearman_server_job_take(gearman_server_con_st *server_con) { - for (gearman_server_worker_st *server_worker= server_con->worker_list; server_worker; server_worker= server_worker->con_next) + for (gearman_server_worker_st *server_worker= server_con->worker_list; server_worker != NULL; server_worker= server_worker->con_next) { - if (server_worker->function and server_worker->function->job_count) + if (server_worker->function != NULL and server_worker->function->job_count) { gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Jobs available for %.*s: %lu", (int)server_worker->function->function_name_size, server_worker->function->function_name, @@ -378,47 +473,49 @@ } } + gearman_server_job_st *server_job= NULL; gearman_job_priority_t priority; - for (priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_LOW; - priority= gearman_job_priority_t(int(priority) +1)) + if (server_job == NULL) { - if (server_worker->function->job_list[priority]) + for (priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; + priority= gearman_job_priority_t(int(priority) +1)) { - break; + if ((server_job= server_worker->function->job_epoch_list[priority]) != NULL and + ((server_job->when <= time(NULL)) or (server_job= NULL))) + { + server_job->function->job_epoch_list[priority]= server_job->function_next; + break; + } } } - - gearman_server_job_st *server_job= server_worker->function->job_list[priority]; - gearman_server_job_st *previous_job= server_job; - - int64_t current_time= (int64_t)time(NULL); - - while (server_job and server_job->when != 0 and server_job->when > current_time) + if (server_job == NULL) { - previous_job= server_job; - server_job= server_job->function_next; - } - - if (server_job) - { - if (server_job->function->job_list[priority] == server_job) + for (priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; + priority= gearman_job_priority_t(int(priority) +1)) { - // If it's the head of the list, advance it - server_job->function->job_list[priority]= server_job->function_next; - } - else - { - // Otherwise, just remove the item from the list - previous_job->function_next= server_job->function_next; + if ((server_job= server_worker->function->job_list[priority]) != NULL) + { + server_job->function->job_list[priority]= server_job->function_next; + break; + } } - - // If it's the tail of the list, move the tail back - if (server_job->function->job_end[priority] == server_job) + } + if (server_job == NULL) + { + for (priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; + priority= gearman_job_priority_t(int(priority) +1)) { - server_job->function->job_end[priority]= previous_job; + if ((server_job= server_worker->function->job_bg_list[priority]) != NULL) + { + server_job->function->job_bg_list[priority]= server_job->function_next; + break; + } } - server_job->function->job_count--; + } + if (server_job != NULL) + { + server_job->function->job_count--; server_job->worker= server_worker; GEARMAND_LIST_ADD(server_worker->job, server_job, worker_); server_job->function->job_running++; @@ -555,6 +652,7 @@ server_job->worker_prev= NULL; server_job->function= NULL; server_job->function_next= NULL; + server_job->function_prev= NULL; server_job->data= NULL; server_job->client_list= NULL; server_job->worker= NULL; --- libgearman-server/gearmand_con.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/gearmand_con.h 2014-08-25 11:56:09.554982218 +0800 @@ -78,11 +78,42 @@ const char *host, const char*, struct gearmand_port_st*); +gearmand_error_t _gearman_server_job_cancel(gearman_server_job_st *server_job); + GEARMAN_API gearmand_error_t gearman_server_job_cancel(gearman_server_st& server, const char *job_handle, const size_t job_handle_length); +GEARMAN_API +gearmand_error_t gearman_server_job_cancel_by_unique(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + +gearmand_error_t _gearman_server_job_clean(gearman_server_job_st *server_job); + +GEARMAN_API +gearmand_error_t gearman_server_job_clean(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + +GEARMAN_API +gearmand_error_t gearman_server_job_clean_by_unique(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + +gearmand_error_t _gearman_server_job_restore(gearman_server_job_st *server_job); + +GEARMAN_API +gearmand_error_t gearman_server_job_restore(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + +GEARMAN_API +gearmand_error_t gearman_server_job_restore_by_unique(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + /** * Free resources used by a connection. * @param dcon Connection previously initialized with gearmand_con_create. --- libgearman-server/gearmand.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/gearmand.h 2014-08-26 00:53:55.961447393 +0800 @@ -107,13 +107,17 @@ const char *host, uint32_t threads, int backlog, - const uint32_t job_retries, const char *job_handle_prefix, - uint8_t worker_wakeup, gearmand_log_fn *function, void *log_context, const gearmand_verbose_t verbose, bool round_robin, bool exceptions_, - uint32_t hashtable_buckets); + uint32_t hashtable_buckets, + struct Options_st &options, + const char *job_retries_action, + const char *job_retries_warn_action, + const char *job_count_max_action, + const char *worker_count_min_action, + const char *worker_failed_action); /** * Free resources used by a server instace. --- libgearman-server/io.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/io.cc 2014-09-01 17:51:55.634048155 +0800 @@ -159,6 +159,12 @@ case SSL_ERROR_SSL: default: { // All other errors +# if defined(HAVE_OPENSSL) && HAVE_OPENSSL + if (ERR_peek_last_error()) + { + ssl_error= ERR_peek_last_error(); + } +# endif char errorString[SSL_ERROR_SIZE]; ERR_error_string_n(ssl_error, errorString, sizeof(errorString)); ret= GEARMAND_LOST_CONNECTION; @@ -338,6 +344,12 @@ case SSL_ERROR_SSL: default: { +# if defined(HAVE_OPENSSL) && HAVE_OPENSSL + if (ERR_peek_last_error()) + { + ssl_error= ERR_peek_last_error(); + } +# endif char errorString[SSL_ERROR_SIZE]; ERR_error_string_n(ssl_error, errorString, sizeof(errorString)); _connection_close(connection); @@ -606,7 +618,11 @@ { return GEARMAND_SUCCESS; } - else if (ret != GEARMAND_FLUSH_DATA) + else if (ret == GEARMAND_FLUSH_DATA) + { + connection->send_buffer_size+= send_size; + } + else { return ret; } @@ -801,8 +817,9 @@ connection->recv_buffer_size+= recv_size; } - if (packet->data_size == 0) + if (packet->data_size == 0 or packet->data_size <= connection->recv_data_offset) { + connection->recv_data_offset= 0; connection->recv_state= gearmand_io_st::GEARMAND_CON_RECV_UNIVERSAL_NONE; break; } @@ -815,17 +832,20 @@ break; } - packet->data= static_cast(realloc(NULL, packet->data_size)); - if (not packet->data) { - // Server up the memory error first, in case _connection_close() - // creates any. - gearmand_merror("realloc", char, packet->data_size); - _connection_close(connection); - return GEARMAND_MEMORY_ALLOCATION_FAILURE; + char *new_data= static_cast(realloc((char *)packet->data, packet->data_size)); + if (new_data == NULL) + { + // Server up the memory error first, in case _connection_close() + // creates any. + gearmand_merror("realloc", char, packet->data_size); + _connection_close(connection); + return GEARMAND_MEMORY_ALLOCATION_FAILURE; + } + packet->data= new_data; + packet->options.free_data= true; } - packet->options.free_data= true; connection->recv_state= gearmand_io_st::GEARMAND_CON_RECV_STATE_READ_DATA; case gearmand_io_st::GEARMAND_CON_RECV_STATE_READ_DATA: --- libgearman-server/job.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/job.cc 2014-09-02 00:20:02.631323690 +0800 @@ -46,6 +46,7 @@ #include "gear_config.h" #include "libgearman-server/common.h" #include +#include #include @@ -172,11 +173,10 @@ if (server_job == NULL) { + uint32_t max_queue_size= (server_function->options.max_queue_size[priority] == 0) ? Server->options.max_queue_size[priority] : server_function->options.max_queue_size[priority]; gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Comparing queue %u to limit %u for priority %u", - server_function->job_total, server_function->max_queue_size[priority], - priority); - if (server_function->max_queue_size[priority] > 0 && - server_function->job_total >= server_function->max_queue_size[priority]) + server_function->job_totals[priority], max_queue_size, priority); + if (max_queue_size > 0 && max_queue_size <= server_function->job_totals[priority]) { *ret_ptr= GEARMAND_JOB_QUEUE_FULL; return NULL; @@ -190,9 +190,10 @@ } server_job->priority= priority; - server_job->function= server_function; + server_function->job_total++; + server_function->job_totals[server_job->priority]++; int checked_length; checked_length= snprintf(server_job->job_handle, GEARMAND_JOB_HANDLE_SIZE, "%s:%u", @@ -247,11 +248,12 @@ else if (server_client == NULL) { *ret_ptr= gearman_queue_add(server, - server_job->unique, unique_size, - function_name, - function_name_size, - data, data_size, priority, - when); + server_job->unique, + server_job->unique_length, + server_job->function->function_name, + server_job->function->function_name_size, + server_job->data, server_job->data_size, + server_job->priority, server_job->when); if (gearmand_failed(*ret_ptr)) { server_job->data= NULL; @@ -269,7 +271,8 @@ { /* Do our best to remove the job from the queue. */ (void)gearman_queue_done(server, - server_job->unique, unique_size, + server_job->unique, + server_job->unique_length, server_job->function->function_name, server_job->function->function_name_size); } @@ -302,6 +305,7 @@ } server_job->function->job_total--; + server_job->function->job_totals[server_job->priority]--; if (server_job->data != NULL) { @@ -339,11 +343,24 @@ gearmand_error_t gearman_server_job_queue(gearman_server_job_st *job) { - if (job->worker) + if (job->worker != NULL) { job->retries++; - if (Server->job_retries != 0 && Server->job_retries == job->retries) + + uint32_t job_retries_warn= (job->function->options.job_retries_warn == 0) ? Server->options.job_retries_warn : job->function->options.job_retries_warn; + if (job_retries_warn != 0 && job_retries_warn <= job->retries && Server->job_retries_warn_action[0] != '\0') + { + gearman_server_notify_job_retries_warn(Server, job); + } + + uint32_t job_retries= (job->function->options.job_retries == 0) ? Server->options.job_retries : job->function->options.job_retries; + if (job_retries != 0 && job_retries <= job->retries) { + if (Server->job_retries_action[0] != '\0') + { + gearman_server_notify_job_retries(Server, job); + } + gearmand_log_notice(GEARMAN_DEFAULT_LOG_PARAM, "Dropped job due to max retry count: %s %.*s", job->job_handle, @@ -367,7 +384,8 @@ if (job->job_queued) { gearmand_error_t ret= gearman_queue_done(Server, - job->unique, job->unique_length, + job->unique, + job->unique_length, job->function->function_name, job->function->function_name_size); if (gearmand_failed(ret)) @@ -389,10 +407,11 @@ } /* Queue NOOP for possible sleeping workers. */ - if (job->function->worker_list != NULL) + if (job->when <= time(NULL) and job->function->worker_list != NULL) { gearman_server_worker_st *worker= job->function->worker_list; uint32_t noop_sent= 0; + uint32_t worker_wakeup= (job->function->options.worker_wakeup == 0) ? Server->options.worker_wakeup : job->function->options.worker_wakeup; do { @@ -414,26 +433,173 @@ worker= worker->function_next; } - while (worker != job->function->worker_list && - (Server->worker_wakeup == 0 || - noop_sent < Server->worker_wakeup)); + while (worker != job->function->worker_list && (worker_wakeup == 0 || worker_wakeup < noop_sent)); job->function->worker_list= worker; } /* Queue the job to be run. */ - if (job->function->job_list[job->priority] == NULL) + if (job->job_queued == false) { - job->function->job_list[job->priority]= job; + if (job->function->job_list[job->priority] == NULL) + { + job->function->job_list[job->priority]= job; + } + else + { + job->function->job_end[job->priority]->function_next= job; + job->function_prev= job->function->job_end[job->priority]; + } + job->function->job_end[job->priority]= job; + } + else if (job->when == 0) + { + if (job->function->job_bg_list[job->priority] == NULL) + { + job->function->job_bg_list[job->priority]= job; + } + else + { + job->function->job_bg_end[job->priority]->function_next= job; + job->function_prev= job->function->job_bg_end[job->priority]; + } + job->function->job_bg_end[job->priority]= job; } else { - job->function->job_end[job->priority]->function_next= job; + gearman_server_job_st *job0= NULL, *job1= job->function->job_epoch_list[job->priority]; + for (; job1 != NULL and job1->when <= job->when; job0= job1, job1= job1->function_next); + if (job0 == NULL) + { + job->function->job_epoch_list[job->priority]= job; + } + else + { + job0->function_next= job; + job->function_prev= job0; + } + if (job1 == NULL) + { + job->function->job_epoch_end[job->priority]= job; + } + else + { + job->function_next= job1; + job1->function_prev= job; + } + + if (job->when > time(NULL)) + { + gearman_server_epoch_job_push(job->when, job->function); + } } - job->function->job_end[job->priority]= job; job->function->job_count++; return GEARMAND_SUCCESS; } #pragma GCC diagnostic pop + +void gearman_server_epoch_job_free(gearman_server_epoch_job_st *epoch_job) +{ + if (epoch_job == NULL) + { + return; + } + gearman_server_epoch_function_st *epoch_function= NULL; + while ((epoch_function= epoch_job->function_list) != NULL) + { + epoch_job->function_list= epoch_function->next; + delete epoch_function; + } + delete epoch_job; +} + +void gearman_server_epoch_job_push(int64_t when, gearman_server_function_st *function) +{ + gearman_server_st *server= gearmand_server(Gearmand()); + if (!server->state.epoch_startup) + { + signal(SIGALRM, gearman_server_epoch_job_pop); + server->state.epoch_startup= true; + } + + gearman_server_epoch_job_st *epoch_job= NULL, *epoch_job0= NULL, *epoch_job1= server->epoch_job_list; + for (; epoch_job1 != NULL and epoch_job1->when <= when; epoch_job0= epoch_job1, epoch_job1= epoch_job1->next); + if (epoch_job0 == NULL or epoch_job0->when < when) + { + epoch_job= new gearman_server_epoch_job_st; + epoch_job->when= when; + epoch_job->next= epoch_job1; + epoch_job->function_list= NULL; + if (epoch_job0 == NULL) + { + server->epoch_job_list= epoch_job; + alarm((epoch_job->when > time(NULL)) ? (epoch_job->when -time(NULL)) : 0); + } + else + { + epoch_job0->next= epoch_job; + } + } + else + { + epoch_job= epoch_job0; + } + + gearman_server_epoch_function_st *epoch_function= NULL, *epoch_function1= epoch_job->function_list; + for (; epoch_function1 != NULL and epoch_function1->function != function; epoch_function1= epoch_function1->next); + if (epoch_function1 == NULL) + { + epoch_function= new gearman_server_epoch_function_st; + epoch_function->function= function; + epoch_function->next= epoch_job->function_list; + epoch_job->function_list= epoch_function; + } +} + +void gearman_server_epoch_job_pop(int) +{ + gearman_server_worker_st *worker= NULL; + gearman_server_epoch_job_st *epoch_job= NULL; + gearman_server_epoch_function_st *epoch_function= NULL; + gearman_server_st *server= gearmand_server(Gearmand()); + while ((epoch_job= server->epoch_job_list) != NULL and epoch_job->when <= time(NULL)) + { + while ((epoch_function= epoch_job->function_list) != NULL) + { + if ((worker= epoch_function->function->worker_list) != NULL) + { + do + { + if (worker->con->is_sleeping and !worker->con->is_noop_sent) + { + gearmand_error_t ret= gearman_server_io_packet_add(worker->con, false, + GEARMAN_MAGIC_RESPONSE, + GEARMAN_COMMAND_NOOP, NULL); + if (gearmand_failed(ret)) + { + gearmand_log_gerror_warn(GEARMAN_DEFAULT_LOG_PARAM, ret, "Failed to send NOOP packet to %s:%s", worker->con->host(), worker->con->port()); + } + else + { + worker->con->is_noop_sent= true; + } + } + } + while ((worker= worker->function_next) != NULL and worker != epoch_function->function->worker_list); + } + + epoch_job->function_list= epoch_function->next; + delete epoch_function; + } + + server->epoch_job_list= epoch_job->next; + delete epoch_job; + } + + if (epoch_job != NULL) + { + alarm((epoch_job->when > time(NULL)) ? (epoch_job->when -time(NULL)) : 0); + } +} --- libgearman-server/job.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/job.h 2014-08-04 21:11:15.388735788 +0800 @@ -128,6 +128,12 @@ GEARMAN_API gearmand_error_t gearman_server_job_queue(gearman_server_job_st *server_job); +void gearman_server_epoch_job_free(gearman_server_epoch_job_st*); + +void gearman_server_epoch_job_push(int64_t, gearman_server_function_st*); + +void gearman_server_epoch_job_pop(int); + uint32_t _server_job_hash(const char *key, size_t key_size); void *_proc(void *data); --- libgearman-server/plugins/base.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/plugins/base.h 2014-08-12 09:52:22.425352472 +0800 @@ -183,6 +183,12 @@ return true; } + // If the protocol only has one response to client + virtual bool is_response_once() const + { + return false; + } + // Notify on disconnect virtual void notify(gearman_server_con_st*) { --- libgearman-server/plugins/protocol/gear/protocol.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/plugins/protocol/gear/protocol.cc 2014-09-01 17:55:28.887372276 +0800 @@ -393,6 +393,12 @@ case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: default: +# if defined(HAVE_OPENSSL) && HAVE_OPENSSL + if (ERR_peek_last_error()) + { + cyassl_error= ERR_peek_last_error(); + } +# endif char cyassl_error_buffer[SSL_ERROR_SIZE]= { 0 }; ERR_error_string_n(cyassl_error, cyassl_error_buffer, sizeof(cyassl_error_buffer)); return gearmand_log_gerror(GEARMAN_DEFAULT_LOG_PARAM, GEARMAND_LOST_CONNECTION, "%s(%d)", @@ -418,9 +424,9 @@ Gear::Gear() : Plugin("Gear"), _port(GEARMAN_DEFAULT_TCP_PORT_STRING), - _ssl_ca_file(GEARMAND_CA_CERTIFICATE), - _ssl_certificate(GEARMAND_SERVER_PEM), - _ssl_key(GEARMAND_SERVER_KEY), + _ssl_ca_file(""), + _ssl_certificate(""), + _ssl_key(""), opt_ssl(false) { command_line_options().add_options() @@ -477,19 +483,40 @@ if (opt_ssl) { - if (getenv("GEARMAND_CA_CERTIFICATE")) + if (_ssl_ca_file.empty()) { - _ssl_ca_file= getenv("GEARMAND_CA_CERTIFICATE"); + if (getenv("GEARMAND_CA_CERTIFICATE")) + { + _ssl_ca_file= getenv("GEARMAND_CA_CERTIFICATE"); + } + else + { + _ssl_ca_file= GEARMAND_CA_CERTIFICATE; + } } - if (getenv("GEARMAND_SERVER_PEM")) + if (_ssl_certificate.empty()) { - _ssl_certificate= getenv("GEARMAND_SERVER_PEM"); + if (getenv("GEARMAND_SERVER_PEM")) + { + _ssl_certificate= getenv("GEARMAND_SERVER_PEM"); + } + else + { + _ssl_certificate= GEARMAND_SERVER_PEM; + } } - if (getenv("GEARMAND_SERVER_KEY")) + if (_ssl_key.empty()) { - _ssl_key= getenv("GEARMAND_SERVER_KEY"); + if (getenv("GEARMAND_SERVER_KEY")) + { + _ssl_key= getenv("GEARMAND_SERVER_KEY"); + } + else + { + _ssl_key= GEARMAND_SERVER_KEY; + } } gearmand->init_ssl(); @@ -512,6 +539,12 @@ } gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Loading certificate key : %s", _ssl_key.c_str()); + if (SSL_CTX_check_private_key(gearmand->ctx_ssl()) != SSL_SUCCESS) + { + gearmand_log_fatal(GEARMAN_DEFAULT_LOG_PARAM, "SSL_CTX_check_private_key() cannot check certificate %s", _ssl_key.c_str()); + } + gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "Checking certificate key : %s", _ssl_key.c_str()); + assert(gearmand->ctx_ssl()); } #endif --- libgearman-server/plugins/protocol/http/protocol.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/plugins/protocol/http/protocol.cc 2014-08-12 17:29:45.585438095 +0800 @@ -73,10 +73,27 @@ class HTTPtext : public gearmand::protocol::Context { public: + struct job_content_st { + char *content; + size_t content_size; + size_t sent_offset; + job_content_st *next; + }; + struct job_contents_st { + char *handle; + size_t handle_size; + bool sent_header; + job_content_st *content_list; + job_content_st *content_end; + size_t content_size; + job_contents_st *prev; + job_contents_st *next; + }; HTTPtext() : + contents_list(NULL), + contents_end(NULL), _method(gearmand::protocol::httpd::TRACE), - _sent_header(false), _background(false), _keep_alive(false), _http_response(gearmand::protocol::httpd::HTTP_OK) @@ -84,7 +101,27 @@ } ~HTTPtext() - { } + { + job_content_st *content= NULL; + job_contents_st *contents= NULL; + while ((contents= contents_list) != NULL) + { + while ((content= contents->content_list) != NULL) + { + contents->content_list= content->next; + delete []content->content; + delete content; + } + contents_list= contents->next; + delete []contents->handle; + delete contents; + } + } + + bool is_response_once() const + { + return true; + } void notify(gearman_server_con_st*) { @@ -96,21 +133,112 @@ void *send_buffer, const size_t send_buffer_size, gearmand_error_t& ret_ptr) { + job_content_st *content= NULL; + job_contents_st *contents= NULL; + switch (packet->command) { + case GEARMAN_COMMAND_JOB_CREATED: + break; + + case GEARMAN_COMMAND_WORK_COMPLETE: + for (contents= contents_list; contents != NULL; contents= contents->next) + { + if (contents->handle_size == packet->arg_size[0] and + memcmp(contents->handle, packet->arg[0], contents->handle_size) == 0) + { + break; + } + } + break; + + case GEARMAN_COMMAND_WORK_FAIL: + case GEARMAN_COMMAND_ECHO_RES: + break; + case GEARMAN_COMMAND_WORK_DATA: + for (contents= contents_list; contents != NULL; contents= contents->next) + { + if (contents->handle_size == packet->arg_size[0] and + memcmp(contents->handle, packet->arg[0], contents->handle_size) == 0) + { + break; + } + } + if (contents == NULL) { - for (const char *ptr= packet->data; ptr <= (packet->data +packet->data_size) -2; ptr++) + if ((contents= new job_contents_st) == NULL) { - content.push_back(*ptr); + gearmand_merror("new job_contents_st", job_contents_st, 0); + ret_ptr= GEARMAND_MEMORY_ALLOCATION_FAILURE; + return 0; } + contents->handle= NULL; + contents->handle_size= packet->arg_size[0]; + contents->sent_header= false; + contents->content_list= NULL; + contents->content_end= NULL; + contents->content_size= 0; + contents->prev= NULL; + contents->next= NULL; - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "HTTP gearmand_command_t: GEARMAN_COMMAND_WORK_DATA length:%" PRIu64, uint64_t(content.size())); - ret_ptr= GEARMAND_IGNORE_PACKET; - return 0; + if ((contents->handle= new char[contents->handle_size]) == NULL) + { + gearmand_merror("new char[]", char, contents->handle_size); + ret_ptr= GEARMAND_MEMORY_ALLOCATION_FAILURE; + delete contents; + return 0; + } + memcpy(contents->handle, packet->arg[0], contents->handle_size); + + if (contents_list == NULL) + { + contents_end= contents_list= contents; + } + else + { + contents_end->next= contents; + contents->prev= contents_end; + contents_end= contents; + } } + if (packet->data_size > 0) + { + if ((content= new job_content_st) == NULL) + { + gearmand_merror("new job_content_st", job_content_st, 0); + ret_ptr= GEARMAND_MEMORY_ALLOCATION_FAILURE; + return 0; + } + content->content= NULL; + content->content_size= packet->data_size; + content->sent_offset= 0; + content->next= NULL; + + if ((content->content= new char[content->content_size]) == NULL) + { + gearmand_merror("new char[]", char, content->content_size); + ret_ptr= GEARMAND_MEMORY_ALLOCATION_FAILURE; + delete content; + return 0; + } + memcpy(content->content, packet->data, content->content_size); + contents->content_size+= content->content_size; + + if (contents->content_list == NULL) + { + contents->content_end= contents->content_list= content; + } + else + { + contents->content_end->next= content; + contents->content_end= content; + } + } + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "HTTP gearmand_command_t: GEARMAN_COMMAND_WORK_DATA length:%" PRIu64 ", total length:%" PRIu64, (uint64_t)content->content_size, (uint64_t)contents->content_size); + ret_ptr= GEARMAND_IGNORE_PACKET; + return 0; - default: case GEARMAN_COMMAND_TEXT: case GEARMAN_COMMAND_CAN_DO: case GEARMAN_COMMAND_CANT_DO: @@ -149,35 +277,25 @@ case GEARMAN_COMMAND_JOB_ASSIGN_ALL: case GEARMAN_COMMAND_GET_STATUS_UNIQUE: case GEARMAN_COMMAND_STATUS_RES_UNIQUE: + case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH: + case GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH: case GEARMAN_COMMAND_MAX: + default: gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Bad packet command: gearmand_command_t:%s", gearman_strcommand(packet->command)); assert(0); - case GEARMAN_COMMAND_WORK_FAIL: - case GEARMAN_COMMAND_ECHO_RES: - case GEARMAN_COMMAND_WORK_COMPLETE: - break; - - case GEARMAN_COMMAND_JOB_CREATED: - { - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, - "Sending HTTP told to ignore packet: gearmand_command_t:%s", - gearman_strcommand(packet->command)); - ret_ptr= GEARMAND_IGNORE_PACKET; - return 0; - } } gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Sending HTTP response: Content-length:%" PRIu64 " data_size:%" PRIu64 " gearmand_command_t:%s response:%s", - uint64_t(content.size()), - uint64_t(packet->data_size), + (uint64_t)((contents == NULL ? 0 : contents->content_size) +packet->data_size), + (uint64_t)packet->data_size, gearman_strcommand(packet->command), gearmand::protocol::httpd::response(response())); size_t pack_size= 0; - if (_sent_header == false) + if (contents == NULL or contents->sent_header == false) { if (response() != gearmand::protocol::httpd::HTTP_OK) { @@ -198,7 +316,7 @@ "\r\n", packet->command == GEARMAN_COMMAND_JOB_CREATED ? (int)packet->arg_size[0] : (int)packet->arg_size[0] - 1, (const char *)packet->arg[0], - (uint64_t)packet->data_size); + (uint64_t)((contents == NULL ? 0 : contents->content_size) +packet->data_size)); } else if (method() == gearmand::protocol::httpd::TRACE) { @@ -215,14 +333,13 @@ "HTTP/1.0 200 OK\r\n" "X-Gearman-Job-Handle: %.*s\r\n" "X-Gearman-Command: %s\r\n" - "Content-Length: %d\r\n" + "Content-Length: %" PRIu64 "\r\n" "Server: Gearman/" PACKAGE_VERSION "\r\n" - "\r\n%.*s", + "\r\n", packet->command == GEARMAN_COMMAND_JOB_CREATED ? int(packet->arg_size[0]) : int(packet->arg_size[0] - 1), (const char *)packet->arg[0], // Job handle gearman_strcommand(packet->command), - int(content.size()), // Content-length - int(content.size()), &content[0]); + (uint64_t)((contents == NULL ? 0 : contents->content_size) +packet->data_size)); // Content-length } else { @@ -236,10 +353,8 @@ packet->command == GEARMAN_COMMAND_JOB_CREATED ? int(packet->arg_size[0]) : int(packet->arg_size[0] - 1), (const char *)packet->arg[0], gearman_strcommand(packet->command), - uint64_t(content.size())); + (uint64_t)((contents == NULL ? 0 : contents->content_size) +packet->data_size)); } - - _sent_header= true; } if (pack_size > send_buffer_size) @@ -249,12 +364,54 @@ return 0; } - memcpy(send_buffer, &content[0], content.size()); - pack_size+= content.size(); + if (contents != NULL) + { + contents->sent_header= true; + size_t content_size= 0; + while ((content= contents->content_list) != NULL) + { + content_size= content->content_size -content->sent_offset; + if (content_size > send_buffer_size -pack_size) + { + content_size= send_buffer_size -pack_size; + } + if (content_size > 0) + { + memcpy((char *)send_buffer +pack_size, content->content +content->sent_offset, content_size); + content->sent_offset+= content_size; + pack_size+= content_size; + } + if (content->sent_offset < content->content_size) + { + gearmand_debug("Sending HTTP had to flush"); + ret_ptr= GEARMAND_FLUSH_DATA; + return pack_size; + } + contents->content_list= content->next; + delete []content->content; + delete content; + } + if (contents == contents_list) + { + contents_list= contents->next; + } + if (contents == contents_end) + { + contents_end= contents->prev; + } + if (contents->prev != NULL) + { + contents->prev->next= contents->next; + } + if (contents->next != NULL) + { + contents->next->prev= contents->prev; + } + delete []contents->handle; + delete contents; + } -#if 0 if (keep_alive() == false) -#endif { gearman_io_set_option(&connection->con, GEARMAND_CON_CLOSE_AFTER_FLUSH, true); } @@ -265,12 +422,15 @@ } size_t unpack(gearmand_packet_st *packet, - gearman_server_con_st *, //connection + gearman_server_con_st *connection, const void *data, const size_t data_size, gearmand_error_t& ret_ptr) { + packet->data_size= 0; const char *unique= "-"; - size_t unique_size= 2; + size_t unique_size= 1; + const char *when= NULL; + size_t when_size= 0; gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_NORMAL; gearmand_info("Receiving HTTP response"); @@ -294,7 +454,7 @@ { gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad request line: %.*s", (uint32_t)request_size, request); set_response(gearmand::protocol::httpd::HTTP_NOT_FOUND); - ret_ptr= GEARMAND_SUCCESS; + ret_ptr= GEARMAND_INVALID_PACKET; return 0; } @@ -330,7 +490,7 @@ { gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "bad method: %.*s", (uint32_t)method_size, method_str); set_response(gearmand::protocol::httpd::HTTP_METHOD_NOT_ALLOWED); - ret_ptr= GEARMAND_SUCCESS; + ret_ptr= GEARMAND_INVALID_PACKET; return 0; } } @@ -361,9 +521,33 @@ gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "HTTP URI: \"%.*s\"", (int)uri_size, uri); switch (method()) { + case gearmand::protocol::httpd::GET: + { + const char *arg= (const char*)memchr(uri, '?', uri_size); + if (arg != NULL) + { + uri_size= arg -uri; + while (*arg == '?' || *arg == '&') + { + arg++; + } + packet->data_size+= (size_t)(version - arg); + char *new_data= static_cast(realloc((char *)packet->data, packet->data_size)); + if (new_data == NULL) + { + gearmand_merror("realloc", char, packet->data_size); + ret_ptr= GEARMAND_MEMORY_ALLOCATION_FAILURE; + return 0; + } + packet->data= new_data; + packet->options.free_data= true; + memcpy((char *)packet->data, arg, packet->data_size); + connection->con.recv_data_offset+= packet->data_size; + } + } + case gearmand::protocol::httpd::POST: case gearmand::protocol::httpd::PUT: - case gearmand::protocol::httpd::GET: if (uri_size == 0) { gearmand_error("must give function name in URI"); @@ -415,7 +599,7 @@ char content_length[11]; /* 11 bytes to fit max display length of uint32_t */ snprintf(content_length, sizeof(content_length), "%.*s", (int)header_size - 16, header + 16); - packet->data_size= size_t(atoi(content_length)); + packet->data_size+= size_t(atoi(content_length)); } } else if (header_size == 22 and @@ -429,6 +613,12 @@ unique= header + 18; unique_size= header_size -18; } + else if (header_size > 16 and + strncasecmp(header, "X-Gearman-When: ", 16) == 0) + { + when= header + 16; + when_size= header_size -16; + } else if (header_size == 26 and strncasecmp(header, "X-Gearman-Background: true", 26) == 0) { @@ -492,7 +682,22 @@ } else { - if (background()) + if (when != NULL and when_size > 0) + { + if (priority == GEARMAN_JOB_PRIORITY_NORMAL) + { + packet->command= GEARMAN_COMMAND_SUBMIT_JOB_EPOCH; + } + else if (priority == GEARMAN_JOB_PRIORITY_HIGH) + { + packet->command= GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH; + } + else + { + packet->command= GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH; + } + } + else if (background()) { if (priority == GEARMAN_JOB_PRIORITY_NORMAL) { @@ -542,6 +747,15 @@ packet->arg[0][uri_size]= 0; packet->arg[1][unique_size]= 0; + if (when != NULL and when_size > 0) + { + if ((ret_ptr= gearmand_packet_create(packet, when, when_size +1)) != GEARMAND_SUCCESS) + { + return 0; + } + packet->arg[2][when_size]= 0; + } + ret_ptr= GEARMAND_SUCCESS; } @@ -592,10 +806,8 @@ void reset() { - _sent_header= false; _background= false; _keep_alive= false; - content.clear(); _method= gearmand::protocol::httpd::TRACE; _http_response= gearmand::protocol::httpd::HTTP_OK; } @@ -624,13 +836,13 @@ } private: + job_contents_st *contents_list; + job_contents_st *contents_end; gearmand::protocol::httpd::method_t _method; - bool _sent_header; bool _background; bool _keep_alive; std::string global_port; gearmand::protocol::httpd::response_t _http_response; - std::vector content; }; static gearmand_error_t _http_con_remove(gearman_server_con_st*) --- libgearman-server/plugins/queue/mysql/queue.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/plugins/queue/mysql/queue.cc 2014-08-18 15:55:19.891842049 +0800 @@ -78,6 +78,10 @@ MYSQL *con; MYSQL_STMT *add_stmt; MYSQL_STMT *done_stmt; + bool mysql_ssl; + std::string mysql_ca; + std::string mysql_cert; + std::string mysql_key; std::string mysql_host; std::string mysql_user; std::string mysql_password; @@ -97,9 +101,17 @@ Queue("MySQL"), con(NULL), add_stmt(NULL), - done_stmt(NULL) + done_stmt(NULL), + mysql_ssl(false), + mysql_ca(""), + mysql_cert(""), + mysql_key("") { command_line_options().add_options() + ("mysql-ssl", boost::program_options::bool_switch(&mysql_ssl)->default_value(false), "MySQL SSL enabled.") + ("mysql-ca", boost::program_options::value(&mysql_ca), "MySQL SSL CA file.") + ("mysql-cert", boost::program_options::value(&mysql_cert), "MySQL SSL certificate file.") + ("mysql-key", boost::program_options::value(&mysql_key), "MySQL SSL key file.") ("mysql-host", boost::program_options::value(&mysql_host)->default_value("localhost"), "MySQL host.") ("mysql-port", boost::program_options::value(&_port)->default_value(3306), "Port of server. (by default 3306)") ("mysql-user", boost::program_options::value(&mysql_user)->default_value(""), "MySQL user.") @@ -129,6 +141,10 @@ { char query_buffer[1024]; + if (this->add_stmt != NULL) + { + mysql_stmt_close(this->add_stmt); + } if ((this->add_stmt= mysql_stmt_init(this->con)) == NULL) { gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_init failed: %s", mysql_error(this->con)); @@ -153,6 +169,10 @@ { char query_buffer[1024]; + if (this->done_stmt != NULL) + { + mysql_stmt_close(this->done_stmt); + } if ((this->done_stmt= mysql_stmt_init(this->con)) == NULL) { gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_init failed: %s", mysql_error(this->con)); @@ -218,6 +238,15 @@ mysql_options(queue->con, MYSQL_READ_DEFAULT_GROUP, "gearmand"); + if (queue->mysql_ssl) + { + mysql_ssl_set(queue->con, + queue->mysql_key.c_str(), + queue->mysql_cert.c_str(), + queue->mysql_ca.c_str(), + NULL, NULL); + } + if (!mysql_real_connect(queue->con, queue->mysql_host.c_str(), queue->mysql_user.c_str(), @@ -329,32 +358,21 @@ { if (mysql_stmt_bind_param(queue->add_stmt, bind)) { - if ( mysql_stmt_errno(queue->add_stmt) == CR_NO_PREPARE_STMT ) + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_bind_param (%.*s %.*s) failed: [%d]%s", function_name_size, function_name, unique_size, unique, mysql_stmt_errno(queue->add_stmt), mysql_stmt_error(queue->add_stmt)); + if (queue->prepareAddStatement() != GEARMAND_QUEUE_ERROR) { - if (queue->prepareAddStatement() == GEARMAND_QUEUE_ERROR) - { - return GEARMAND_QUEUE_ERROR; - } continue; } - else - { - gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_bind_param failed: %s", mysql_error(queue->con)); - return GEARMAND_QUEUE_ERROR; - } + return GEARMAND_QUEUE_ERROR; } if (mysql_stmt_execute(queue->add_stmt)) { - if ( mysql_stmt_errno(queue->add_stmt) == CR_SERVER_LOST ) + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_execute (%.*s %.*s) failed: [%d]%s", function_name_size, function_name, unique_size, unique, mysql_stmt_errno(queue->add_stmt), mysql_stmt_error(queue->add_stmt)); + if (queue->prepareAddStatement() != GEARMAND_QUEUE_ERROR) { - mysql_stmt_close(queue->add_stmt); - if (queue->prepareAddStatement() != GEARMAND_QUEUE_ERROR) - { - continue; - } + continue; } - gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_execute failed: %s", mysql_error(queue->con)); return GEARMAND_QUEUE_ERROR; } @@ -378,7 +396,6 @@ const char *function_name, size_t function_name_size) { - MYSQL_BIND bind[2]; gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM,"MySQL queue done: %.*s %.*s", (uint32_t) unique_size, (char *) unique, @@ -402,33 +419,21 @@ { if (mysql_stmt_bind_param(queue->done_stmt, bind)) { - if ( mysql_stmt_errno(queue->done_stmt) == CR_NO_PREPARE_STMT ) + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_bind_param (%.*s %.*s) failed: [%d]%s", function_name_size, function_name, unique_size, unique, mysql_stmt_errno(queue->done_stmt), mysql_stmt_error(queue->done_stmt)); + if (queue->prepareDoneStatement() != GEARMAND_QUEUE_ERROR) { - if (queue->prepareDoneStatement() == GEARMAND_QUEUE_ERROR) - { - return GEARMAND_QUEUE_ERROR; - } continue; } - else - { - gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_bind_param failed: %s", mysql_error(queue->con)); - return GEARMAND_QUEUE_ERROR; - } + return GEARMAND_QUEUE_ERROR; } if (mysql_stmt_execute(queue->done_stmt)) { - if ( mysql_stmt_errno(queue->done_stmt) == CR_SERVER_LOST ) + gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_execute (%.*s %.*s) failed: [%d]%s", function_name_size, function_name, unique_size, unique, mysql_stmt_errno(queue->done_stmt), mysql_stmt_error(queue->done_stmt)); + if (queue->prepareDoneStatement() != GEARMAND_QUEUE_ERROR) { - mysql_stmt_close(queue->done_stmt); - if (queue->prepareDoneStatement() != GEARMAND_QUEUE_ERROR) - { - continue; - } + continue; } - gearmand_log_error(GEARMAN_DEFAULT_LOG_PARAM, "mysql_stmt_execute failed: %s", mysql_error(queue->con)); - return GEARMAND_QUEUE_ERROR; } --- libgearman-server/server.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/server.cc 2014-08-12 09:48:59.225350624 +0800 @@ -56,6 +56,7 @@ #include "libgearman-1.0/return.h" #include "libgearman-1.0/strerror.h" #include "libgearman/magic.h" +#include "libgearman/command.h" /* * Private declarations @@ -205,11 +206,13 @@ /* Client requests. */ case GEARMAN_COMMAND_SUBMIT_JOB: case GEARMAN_COMMAND_SUBMIT_JOB_BG: + case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH: case GEARMAN_COMMAND_SUBMIT_JOB_HIGH: case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG: + case GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH: case GEARMAN_COMMAND_SUBMIT_JOB_LOW: case GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG: - case GEARMAN_COMMAND_SUBMIT_JOB_EPOCH: + case GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH: { gearman_job_priority_t priority; @@ -220,7 +223,8 @@ priority= GEARMAN_JOB_PRIORITY_NORMAL; } else if (packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH or - packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG) + packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG or + packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH) { priority= GEARMAN_JOB_PRIORITY_HIGH; } @@ -232,7 +236,9 @@ if (packet->command == GEARMAN_COMMAND_SUBMIT_JOB_BG or packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_BG or packet->command == GEARMAN_COMMAND_SUBMIT_JOB_LOW_BG or - packet->command == GEARMAN_COMMAND_SUBMIT_JOB_EPOCH) + packet->command == GEARMAN_COMMAND_SUBMIT_JOB_EPOCH or + packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH or + packet->command == GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH) { server_client= NULL; } @@ -251,7 +257,9 @@ packet->arg_size[1], packet->arg[1], (int)packet->argc); int64_t when= 0; - if (packet->command == GEARMAN_COMMAND_SUBMIT_JOB_EPOCH) + if (packet->command == GEARMAN_COMMAND_SUBMIT_JOB_EPOCH or + packet->command == GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH or + packet->command == GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH) { char *endptr; // @note stroll will set errno if error, but it might also leave errno @@ -303,15 +311,18 @@ } /* 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 (gearmand_failed(ret)) + if (server_con->protocol->is_response_once() == false or server_client == NULL) { - gearman_server_client_free(server_client); - return gearmand_gerror("gearman_server_io_packet_add", ret); + 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 (gearmand_failed(ret)) + { + gearman_server_client_free(server_client); + return gearmand_gerror("gearman_server_io_packet_add", ret); + } } gearmand_log_notice(GEARMAN_DEFAULT_LOG_PARAM,"accepted,%.*s,%.*s,%jd", @@ -1065,7 +1076,7 @@ if (gearmand_failed(ret)) { - gearmand_log_gerror_warn(GEARMAN_DEFAULT_LOG_PARAM, ret, "Failed to send WORK_FAIL packet to %s:%s", server_client->con->host(), server_client->con->port()); + gearmand_log_gerror_warn(GEARMAN_DEFAULT_LOG_PARAM, ret, "Failed to send %s packet to %s:%s", gearman_enum_strcommand(command), server_client->con->host(), server_client->con->port()); } } --- libgearman-server/struct/function.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/struct/function.h 2014-09-02 00:05:41.614694216 +0800 @@ -37,19 +37,42 @@ #pragma once +struct Options_st { + uint32_t job_retries; // Set maximum job retry count when an action will be taken. + uint32_t job_retries_warn; // Set maximum job retry count when an action will be taken. + uint32_t job_count_max; // Set maximum job count when an action will be taken. + uint32_t job_count_max_interval; // Set interval of actions for job_count_max. + uint32_t worker_count_min; // Set min worker count when an action will be taken. + uint32_t worker_count_min_interval; // Set interval of actions for worker_count_min. + uint32_t worker_wakeup; // Set maximum number of workers to wake up per job. + uint32_t max_queue_size[GEARMAN_JOB_PRIORITY_MAX]; // Set maximum number of jobs. +}; + struct gearman_server_function_st { uint32_t worker_count; uint32_t job_count; uint32_t job_total; uint32_t job_running; - uint32_t max_queue_size[GEARMAN_JOB_PRIORITY_MAX]; size_t function_name_size; gearman_server_function_st *next; gearman_server_function_st *prev; char *function_name; gearman_server_worker_st *worker_list; + struct gearman_server_job_st *job_epoch_list[GEARMAN_JOB_PRIORITY_MAX]; + struct gearman_server_job_st *job_epoch_end[GEARMAN_JOB_PRIORITY_MAX]; + struct gearman_server_job_st *job_bg_list[GEARMAN_JOB_PRIORITY_MAX]; + struct gearman_server_job_st *job_bg_end[GEARMAN_JOB_PRIORITY_MAX]; struct gearman_server_job_st *job_list[GEARMAN_JOB_PRIORITY_MAX]; - gearman_server_job_st *job_end[GEARMAN_JOB_PRIORITY_MAX]; + struct gearman_server_job_st *job_end[GEARMAN_JOB_PRIORITY_MAX]; + uint32_t job_totals[GEARMAN_JOB_PRIORITY_MAX]; + struct Options_st options; + timer_t job_count_max_timer; + timer_t worker_count_min_timer; }; +struct gearman_server_epoch_function_st +{ + gearman_server_function_st *function; + gearman_server_epoch_function_st *next; +}; --- libgearman-server/struct/io.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/struct/io.h 2014-09-01 23:54:12.414723989 +0800 @@ -171,6 +171,9 @@ struct gearman_server_client_st *client_list; const char *_host; // client host const char *_port; // client port + char *_function_names; + uint32_t _function_names_size; + uint32_t _function_names_count; char id[GEARMAND_SERVER_CON_ID_SIZE]; gearmand::protocol::Context* protocol; struct event *timeout_event; --- libgearman-server/struct/job.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/struct/job.h 2014-08-25 15:06:09.531865909 +0800 @@ -60,6 +60,7 @@ gearman_server_job_st *worker_prev; gearman_server_function_st *function; gearman_server_job_st *function_next; + gearman_server_job_st *function_prev; const void *data; gearman_server_client_st *client_list; gearman_server_worker_st *worker; @@ -68,3 +69,10 @@ char unique[GEARMAN_MAX_UNIQUE_SIZE]; char reducer[GEARMAN_FUNCTION_MAX_SIZE]; }; + +struct gearman_server_epoch_job_st +{ + int64_t when; + gearman_server_epoch_job_st *next; + gearman_server_epoch_function_st *function_list; +}; --- libgearman-server/struct/server.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/struct/server.h 2014-08-26 00:19:11.101537455 +0800 @@ -80,13 +80,12 @@ } flags; struct State { bool queue_startup; + bool epoch_startup; } state; bool shutdown; bool shutdown_graceful; bool proc_wakeup; bool proc_shutdown; - uint32_t job_retries; // Set maximum job retry count. - uint8_t worker_wakeup; // Set maximum number of workers to wake up per job. uint32_t job_handle_count; uint32_t thread_count; uint32_t function_count; @@ -111,6 +110,13 @@ uint32_t hashtable_buckets; gearman_server_job_st **job_hash; gearman_server_job_st **unique_hash; + gearman_server_epoch_job_st *epoch_job_list; + struct Options_st options; + char job_retries_action[GEARMAND_ACTION_SIZE]; + char job_retries_warn_action[GEARMAND_ACTION_SIZE]; + char job_count_max_action[GEARMAND_ACTION_SIZE]; + char worker_count_min_action[GEARMAND_ACTION_SIZE]; + char worker_failed_action[GEARMAND_ACTION_SIZE]; gearman_server_st() { --- libgearman-server/text.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/text.cc 2014-09-02 00:49:06.121248376 +0800 @@ -46,13 +46,374 @@ #include #include +#define TEXT_END ".\r\n" #define TEXT_SUCCESS "OK\r\n" #define TEXT_ERROR_ARGS "ERR INVALID_ARGUMENTS An+incomplete+set+of+arguments+was+sent+to+this+command+%.*s\r\n" #define TEXT_ERROR_CREATE_FUNCTION "ERR CREATE_FUNCTION %.*s\r\n" #define TEXT_ERROR_UNKNOWN_COMMAND "ERR UNKNOWN_COMMAND Unknown+server+command%.*s\r\n" #define TEXT_ERROR_INTERNAL_ERROR "ERR UNKNOWN_ERROR\r\n" +#define TEXT_ERROR_UNKNOWN_CANCEL_ARGUMENTS "ERR UNKNOWN_CANCEL_ARGUMENTS\r\n" +#define TEXT_ERROR_UNKNOWN_CLEAN_ARGUMENTS "ERR UNKNOWN_CLEAN_ARGUMENTS\r\n" +#define TEXT_ERROR_UNKNOWN_RESTORE_ARGUMENTS "ERR UNKNOWN_RESTORE_ARGUMENTS\r\n" #define TEXT_ERROR_UNKNOWN_SHOW_ARGUMENTS "ERR UNKNOWN_SHOW_ARGUMENTS\r\n" +#define TEXT_ERROR_UNKNOWN_CONFIG_ARGUMENTS "ERR UNKNOWN_CONFIG_ARGUMENTS\r\n" +#define TEXT_ERROR_UNKNOWN_CREATE_ARGUMENTS "ERR UNKNOWN_CREATE_ARGUMENTS\r\n" +#define TEXT_ERROR_UNKNOWN_DROP_ARGUMENTS "ERR UNKNOWN_DROP_ARGUMENTS\r\n" #define TEXT_ERROR_UNKNOWN_JOB "ERR UNKNOWN_JOB\r\n" +#define TEXT_ERROR_UNKNOWN_FUNCTION "ERR UNKNOWN_FUNCTION\r\n" +#define TEXT_ERROR_JOB_CANCELED "ERR JOB_CANCELED\r\n" +#define TEXT_ERROR_JOB_NOT_CANCELED "ERR JOB_NOT_CANCELED\r\n" +#define TEXT_ERROR_FUNCTION_HAS_WORKER "ERR FUNCTION_HAS_WORKER\r\n" + +static void status_server_function(gearman_vector_st &data, gearman_server_function_st *server_function) +{ + data.vec_append_printf("%.*s\t%u\t%u\t%u", + server_function->function_name_size, server_function->function_name, + server_function->job_total, server_function->job_running, server_function->worker_count); + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= (gearman_job_priority_t)((int)priority +1)) + { + data.vec_append_printf("\t%u", server_function->job_totals[priority]); + } + data.vec_append_printf("\r\n"); +} + +static void cancel_server_job_unique(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_cancel(server_job); + if (ret == GEARMAND_SUCCESS) + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_SUCCESS); + } + else if (ret == GEARMAND_JOB_CANCELED) + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_JOB_CANCELED); + } + else + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void cancel_server_job_handle(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_cancel(server_job); + if (ret == GEARMAND_SUCCESS) + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_SUCCESS); + } + else if (ret == GEARMAND_JOB_CANCELED) + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_JOB_CANCELED); + } + else + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void clean_server_job_unique(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + data.vec_append_printf("%.*s\t", server_job->unique_length, server_job->unique); + gearmand_error_t ret= _gearman_server_job_clean(server_job); + if (ret == GEARMAND_SUCCESS) + { + data.vec_append_printf("%s", TEXT_SUCCESS); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_append_printf("%s", TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_append_printf("%s", TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void clean_server_job_handle(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + data.vec_append_printf("%s\t", server_job->job_handle); + gearmand_error_t ret= _gearman_server_job_clean(server_job); + if (ret == GEARMAND_SUCCESS) + { + data.vec_append_printf("%s", TEXT_SUCCESS); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_append_printf("%s", TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_append_printf("%s", TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void restore_server_job_unique(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_restore(server_job); + if (ret == GEARMAND_SUCCESS) + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_SUCCESS); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void restore_server_job_handle(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_restore(server_job); + if (ret == GEARMAND_SUCCESS) + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_SUCCESS); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void show_server_job_unique(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + char when[20] = "0000-00-00 00:00:00"; + if (server_job->when > 0) + { + struct tm t; + strftime(when, 20, "%Y-%m-%d %H:%M:%S", localtime_r(&(server_job->when), &t)); + } + data.vec_append_printf("%.*s\t%d\t%d\t%d\t%s\t%d\t%d\t%d\t%d\t%s\t%.*s\r\n", + server_job->unique_length, server_job->unique, + server_job->retries, server_job->ignore_job, server_job->job_queued, + when, server_job->priority, + (server_job->worker == NULL) ? 0 : 1, server_job->numerator, server_job->denominator, + server_job->job_handle, + server_job->function->function_name_size, server_job->function->function_name); +} + +static void show_server_job_handle(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + char when[20] = "0000-00-00 00:00:00"; + if (server_job->when > 0) + { + struct tm t; + strftime(when, 20, "%Y-%m-%d %H:%M:%S", localtime_r(&(server_job->when), &t)); + } + data.vec_append_printf("%s\t%d\t%d\t%d\t%s\t%d\t%d\t%d\t%d\t%.*s\t%.*s\r\n", + server_job->job_handle, + server_job->retries, server_job->ignore_job, server_job->job_queued, + when, server_job->priority, + (server_job->worker == NULL) ? 0 : 1, server_job->numerator, server_job->denominator, + server_job->unique_length, server_job->unique, + server_job->function->function_name_size, server_job->function->function_name); +} + +struct Options_use_st { + bool job_retries; + bool job_retries_warn; + bool job_count_max; + bool job_count_max_interval; + bool worker_count_min; + bool worker_count_min_interval; + bool worker_wakeup; + bool max_queue_size[GEARMAN_JOB_PRIORITY_MAX]; +}; + +static void parse_options(const char *argv, struct Options_st &options, struct Options_use_st &options_use) +{ + options_use.job_retries= false; + options_use.job_retries_warn= false; + options_use.job_count_max= false; + options_use.job_count_max_interval= false; + options_use.worker_count_min= false; + options_use.worker_count_min_interval= false; + options_use.worker_wakeup= false; + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= (gearman_job_priority_t)((int)priority +1)) + { + options_use.max_queue_size[priority]= false; + } + + char *args= (char *)argv; + int64_t size= strlen(argv); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + char *equal= (char *)memchr(args, '=', length); + int64_t klength= (equal == NULL) ? length : (equal -args); + int64_t vlength= (length > klength +1) ? (length -klength -1) : 0; + if (klength > 0) + { + if (klength == 11 and strncasecmp("job_retries", args, klength) == 0) + { + options_use.job_retries= true; + options.job_retries= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + else if (klength == 16 and strncasecmp("job_retries_warn", args, klength) == 0) + { + options_use.job_retries_warn= true; + options.job_retries_warn= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + else if (klength == 13 and strncasecmp("job_count_max", args, klength) == 0) + { + options_use.job_count_max= true; + options.job_count_max= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + else if (klength == 22 and strncasecmp("job_count_max_interval", args, klength) == 0) + { + options_use.job_count_max_interval= true; + options.job_count_max_interval= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + else if (klength == 16 and strncasecmp("worker_count_min", args, klength) == 0) + { + options_use.worker_count_min= true; + options.worker_count_min= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + else if (klength == 25 and strncasecmp("worker_count_min_interval", args, klength) == 0) + { + options_use.worker_count_min_interval= true; + options.worker_count_min_interval= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + else if (klength == 13 and strncasecmp("worker_wakeup", args, klength) == 0) + { + options_use.worker_wakeup= true; + options.worker_wakeup= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + else if (klength == 16 and strncasecmp("max_queue_size_", args, klength -1) == 0) + { + gearman_job_priority_t priority= (gearman_job_priority_t)atoi(args +klength -1); + if (priority >= 0 and priority < GEARMAN_JOB_PRIORITY_MAX) + { + options_use.max_queue_size[priority]= true; + options.max_queue_size[priority]= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + } + } + } + } + args+= (length +1); + size-= (length +1); + } +} + +static void apply_options(gearman_server_function_st *server_function, struct Options_st &new_options, struct Options_use_st &options_use) +{ + struct Options_st &options= (server_function != NULL) ? server_function->options : Server->options; + if (options_use.job_retries == true) + { + options.job_retries= new_options.job_retries; + } + if (options_use.job_retries_warn == true) + { + options.job_retries_warn= new_options.job_retries_warn; + } + if (options_use.job_count_max == true) + { + options.job_count_max= new_options.job_count_max; + } + if (options_use.job_count_max_interval == true) + { + options.job_count_max_interval= new_options.job_count_max_interval; + } + if (options_use.worker_count_min == true) + { + options.worker_count_min= new_options.worker_count_min; + } + if (options_use.worker_count_min_interval == true) + { + options.worker_count_min_interval= new_options.worker_count_min_interval; + } + if (options_use.worker_wakeup == true) + { + options.worker_wakeup= new_options.worker_wakeup; + } + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= (gearman_job_priority_t)((int)priority +1)) + { + if (options_use.max_queue_size[priority] == true) + { + options.max_queue_size[priority]= new_options.max_queue_size[priority]; + } + } + + if (server_function != NULL) + { + if (options_use.job_count_max == true or options_use.job_count_max_interval == true) + { + gearman_server_timer_job_count_max(Server, server_function); + } + if (options_use.worker_count_min == true or options_use.worker_count_min_interval == true) + { + gearman_server_timer_worker_count_min(Server, server_function); + } + } + else + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (server_function= Server->function_hash[x]; server_function != NULL; server_function= server_function->next) + { + if (options_use.job_count_max == true or options_use.job_count_max_interval == true) + { + gearman_server_timer_job_count_max(Server, server_function); + } + if (options_use.worker_count_min == true or options_use.worker_count_min_interval == true) + { + gearman_server_timer_worker_count_min(Server, server_function); + } + } + } + } +} + +static void print_options(gearman_vector_st &data, gearman_server_function_st *server_function) +{ + if (server_function != NULL) + { + data.vec_append_printf("%.*s\t", server_function->function_name_size, server_function->function_name); + } + struct Options_st &options= (server_function != NULL) ? server_function->options : Server->options; + data.vec_append_printf("%d\t%d\t%d\t%d\t%d\t%d\t%d", + options.job_retries, options.job_retries_warn, options.job_count_max, options.job_count_max_interval, + options.worker_count_min, options.worker_count_min_interval, options.worker_wakeup); + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= (gearman_job_priority_t)((int)priority +1)) + { + data.vec_append_printf("\t%d", options.max_queue_size[priority]); + } + data.vec_append_printf("\r\n"); +} + +static void free_server_function_jobs(gearman_server_function_st *server_function) +{ + if (server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + _gearman_server_job_cancel(server_job); + gearman_server_job_free(server_job); + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + _gearman_server_job_cancel(server_job); + gearman_server_job_free(server_job); + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + _gearman_server_job_cancel(server_job); + gearman_server_job_free(server_job); + } + } + } +} gearmand_error_t server_run_text(gearman_server_con_st *server_con, gearmand_packet_st *packet) @@ -117,149 +478,1096 @@ } } - data.vec_append_printf(".\n"); + data.vec_append_printf(TEXT_END); } - else if (strcasecmp("status", (char *)(packet->arg[0])) == 0) + else if (strcasecmp("status", packet->arg[0]) == 0) { - for (uint32_t function_key= 0; - function_key < GEARMAND_DEFAULT_HASH_SIZE; - function_key++) + if (packet->argc >= 2 and strcasecmp("-", packet->arg[1]) != 0) + { + char *args= packet->arg[1]; + int64_t size= strlen(packet->arg[1]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL) + { + status_server_function(data, server_function); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_FUNCTION); + } + } + args+= (length +1); + size-= (length +1); + } + } + else { - for (gearman_server_function_st *function= Server->function_hash[function_key]; - function != NULL; - function= function->next) + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) { - data.vec_append_printf("%.*s\t%u\t%u\t%u\n", - int(function->function_name_size), - function->function_name, function->job_total, - function->job_running, function->worker_count); + for (gearman_server_function_st *server_function= Server->function_hash[x]; server_function != NULL; server_function= server_function->next) + { + status_server_function(data, server_function); + } } } - - data.vec_append_printf(".\n"); + data.vec_append_printf(TEXT_END); } - else if (packet->argc >= 3 - and strcasecmp("cancel", (char *)(packet->arg[0])) == 0) + else if (strcasecmp("cancel", packet->arg[0]) == 0) { - if (packet->argc == 3 - and strcasecmp("job", (char *)(packet->arg[1])) == 0) + if (packet->argc >= 4 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("job", packet->arg[2]) == 0) { - gearmand_error_t ret= gearman_server_job_cancel(Gearmand()->server, packet->arg[2], strlen(packet->arg[2])); - + gearmand_error_t ret= gearman_server_job_cancel_by_unique(Gearmand()->server, packet->arg[3], strlen(packet->arg[3])); if (ret == GEARMAND_SUCCESS) { data.vec_printf(TEXT_SUCCESS); } - else if (ret != GEARMAND_NO_JOBS) + else if (ret == GEARMAND_NO_JOBS) { - data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_CANCELED) + { + data.vec_printf(TEXT_ERROR_JOB_CANCELED); } else { - data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); } } - } - else if (packet->argc >= 2 and strcasecmp("show", (char *)(packet->arg[0])) == 0) - { - if (packet->argc == 3 - and strcasecmp("unique", (char *)(packet->arg[1])) == 0 - and strcasecmp("jobs", (char *)(packet->arg[2])) == 0) + else if (packet->argc >= 3 and strcasecmp("job", packet->arg[1]) == 0) { - for (size_t x= 0; x < Server->hashtable_buckets; x++) + gearmand_error_t ret= gearman_server_job_cancel(Gearmand()->server, packet->arg[2], strlen(packet->arg[2])); + if (ret == GEARMAND_SUCCESS) { - for (gearman_server_job_st* server_job= Server->unique_hash[x]; - server_job != NULL; - server_job= server_job->unique_next) - { - data.vec_append_printf("%.*s\n", int(server_job->unique_length), server_job->unique); - } + data.vec_printf(TEXT_SUCCESS); + } + else if (ret == GEARMAND_NO_JOBS) + { + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_CANCELED) + { + data.vec_printf(TEXT_ERROR_JOB_CANCELED); + } + else + { + data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); } - - data.vec_append_printf(".\n"); } - else if (packet->argc == 2 - and strcasecmp("jobs", (char *)(packet->arg[1])) == 0) + else if (packet->argc >= 3 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("jobs", packet->arg[2]) == 0) { - for (size_t x= 0; x < Server->hashtable_buckets; ++x) + if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) { - for (gearman_server_job_st *server_job= Server->job_hash[x]; - server_job != NULL; - server_job= server_job->next) + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) { - data.vec_append_printf("%s\t%u\t%u\t%u\n", server_job->job_handle, uint32_t(server_job->retries), - uint32_t(server_job->ignore_job), uint32_t(server_job->job_queued)); + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_job_st *server_job= gearman_server_job_get_by_unique(Server, args, length, NULL); + if (server_job != NULL) + { + cancel_server_job_unique(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } + } + args+= (length +1); + size-= (length +1); } } - - data.vec_append_printf(".\n"); - } - else - { - data.vec_printf(TEXT_ERROR_UNKNOWN_SHOW_ARGUMENTS); - } - } - else if (strcasecmp("create", (char *)(packet->arg[0])) == 0) - { - if (packet->argc == 3 and strcasecmp("function", (char *)(packet->arg[1])) == 0) - { - gearman_server_function_st* function= gearman_server_function_get(Server, (char *)(packet->arg[2]), packet->arg_size[2] -2); - - if (function) + else if (packet->argc >= 5 and strcasecmp("-", packet->arg[4]) != 0) { - data.vec_printf(TEXT_SUCCESS); + char *args= packet->arg[4]; + int64_t size= strlen(packet->arg[4]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_unique(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_unique(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_unique(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); + } } else { - data.vec_printf(TEXT_ERROR_CREATE_FUNCTION, - (int)packet->arg_size[2], (char *)(packet->arg[2])); + for (size_t x= 0; x < Server->hashtable_buckets; x++) + { + for (gearman_server_job_st* server_job= Server->unique_hash[x]; server_job != NULL; server_job= server_job->unique_next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_unique(data, server_job); + } + } + } } + data.vec_append_printf(TEXT_END); } - else - { - // create - data.vec_printf(TEXT_ERROR_ARGS, (int)packet->arg_size[0], (char *)(packet->arg[0])); - } - } - else if (strcasecmp("drop", (char *)(packet->arg[0])) == 0) - { - if (packet->argc == 3 and strcasecmp("function", (char *)(packet->arg[1])) == 0) + else if (packet->argc >= 2 and strcasecmp("jobs", packet->arg[1]) == 0) { - bool success= false; - for (uint32_t function_key= 0; function_key < GEARMAND_DEFAULT_HASH_SIZE; - function_key++) + if (packet->argc >= 3 and strcasecmp("-", packet->arg[2]) != 0) { - for (gearman_server_function_st *function= Server->function_hash[function_key]; - function != NULL; - function= function->next) + char *args= packet->arg[2]; + int64_t size= strlen(packet->arg[2]); + while (size > 0) { - if (strcasecmp(function->function_name, (char *)(packet->arg[2])) == 0) + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) { - success= true; - if (function->worker_count == 0 && function->job_running == 0) + gearman_server_job_st *server_job= gearman_server_job_get(Server, args, length, NULL); + if (server_job != NULL) { - gearman_server_function_free(Server, function); - data.vec_append_printf(TEXT_SUCCESS); + cancel_server_job_handle(data, server_job); } else { - data.vec_append_printf("ERR there are still connected workers or executing clients\r\n"); + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); } - break; } + args+= (length +1); + size-= (length +1); } } - - if (success == false) + else if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) + { + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_handle(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_handle(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_handle(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; ++x) + { + for (gearman_server_job_st *server_job= Server->job_hash[x]; server_job != NULL; server_job= server_job->next) + { + if (server_job->ignore_job == false) + { + cancel_server_job_handle(data, server_job); + } + } + } + } + data.vec_append_printf(TEXT_END); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_CANCEL_ARGUMENTS); + } + } + else if (strcasecmp("clean", packet->arg[0]) == 0) + { + if (packet->argc >= 4 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("job", packet->arg[2]) == 0) + { + gearmand_error_t ret= gearman_server_job_clean_by_unique(Gearmand()->server, packet->arg[3], strlen(packet->arg[3])); + if (ret == GEARMAND_SUCCESS) + { + data.vec_printf(TEXT_SUCCESS); + } + else if (ret == GEARMAND_NO_JOBS) { - data.vec_printf("ERR function not found\r\n"); - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s", data.value()); + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_printf(TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); + } + } + else if (packet->argc >= 3 and strcasecmp("job", packet->arg[1]) == 0) + { + gearmand_error_t ret= gearman_server_job_clean(Gearmand()->server, packet->arg[2], strlen(packet->arg[2])); + if (ret == GEARMAND_SUCCESS) + { + data.vec_printf(TEXT_SUCCESS); + } + else if (ret == GEARMAND_NO_JOBS) + { + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_printf(TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); + } + } + else if (packet->argc >= 3 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("jobs", packet->arg[2]) == 0) + { + if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) + { + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_job_st *server_job= gearman_server_job_get_by_unique(Server, args, length, NULL); + if (server_job != NULL) + { + clean_server_job_unique(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } + } + args+= (length +1); + size-= (length +1); + } + } + else if (packet->argc >= 5 and strcasecmp("-", packet->arg[4]) != 0) + { + char *args= packet->arg[4]; + int64_t size= strlen(packet->arg[4]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + clean_server_job_unique(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + clean_server_job_unique(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + clean_server_job_unique(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; x++) + { + for (gearman_server_job_st* server_job= Server->unique_hash[x]; server_job != NULL; server_job= server_job->unique_next) + { + if (server_job->ignore_job == true) + { + clean_server_job_unique(data, server_job); + } + } + } + } + data.vec_append_printf(TEXT_END); + } + else if (packet->argc >= 2 and strcasecmp("jobs", packet->arg[1]) == 0) + { + if (packet->argc >= 3 and strcasecmp("-", packet->arg[2]) != 0) + { + char *args= packet->arg[2]; + int64_t size= strlen(packet->arg[2]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_job_st *server_job= gearman_server_job_get(Server, args, length, NULL); + if (server_job != NULL) + { + clean_server_job_handle(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } + } + args+= (length +1); + size-= (length +1); + } + } + else if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) + { + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + clean_server_job_handle(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + clean_server_job_handle(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + clean_server_job_handle(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; ++x) + { + for (gearman_server_job_st *server_job= Server->job_hash[x]; server_job != NULL; server_job= server_job->next) + { + if (server_job->ignore_job == true) + { + clean_server_job_handle(data, server_job); + } + } + } + } + data.vec_append_printf(TEXT_END); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_CLEAN_ARGUMENTS); + } + } + else if (strcasecmp("restore", packet->arg[0]) == 0) + { + if (packet->argc >= 4 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("job", packet->arg[2]) == 0) + { + gearmand_error_t ret= gearman_server_job_restore_by_unique(Gearmand()->server, packet->arg[3], strlen(packet->arg[3])); + if (ret == GEARMAND_SUCCESS) + { + data.vec_printf(TEXT_SUCCESS); + } + else if (ret == GEARMAND_NO_JOBS) + { + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_printf(TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); + } + } + else if (packet->argc >= 3 and strcasecmp("job", packet->arg[1]) == 0) + { + gearmand_error_t ret= gearman_server_job_restore(Gearmand()->server, packet->arg[2], strlen(packet->arg[2])); + if (ret == GEARMAND_SUCCESS) + { + data.vec_printf(TEXT_SUCCESS); + } + else if (ret == GEARMAND_NO_JOBS) + { + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_NOT_CANCELED) + { + data.vec_printf(TEXT_ERROR_JOB_NOT_CANCELED); + } + else + { + data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); + } + } + else if (packet->argc >= 3 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("jobs", packet->arg[2]) == 0) + { + if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) + { + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_job_st *server_job= gearman_server_job_get_by_unique(Server, args, length, NULL); + if (server_job != NULL) + { + restore_server_job_unique(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } + } + args+= (length +1); + size-= (length +1); + } + } + else if (packet->argc >= 5 and strcasecmp("-", packet->arg[4]) != 0) + { + char *args= packet->arg[4]; + int64_t size= strlen(packet->arg[4]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + restore_server_job_unique(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + restore_server_job_unique(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + restore_server_job_unique(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; x++) + { + for (gearman_server_job_st* server_job= Server->unique_hash[x]; server_job != NULL; server_job= server_job->unique_next) + { + if (server_job->ignore_job == true) + { + restore_server_job_unique(data, server_job); + } + } + } + } + data.vec_append_printf(TEXT_END); + } + else if (packet->argc >= 2 and strcasecmp("jobs", packet->arg[1]) == 0) + { + if (packet->argc >= 3 and strcasecmp("-", packet->arg[2]) != 0) + { + char *args= packet->arg[2]; + int64_t size= strlen(packet->arg[2]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_job_st *server_job= gearman_server_job_get(Server, args, length, NULL); + if (server_job != NULL) + { + restore_server_job_handle(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } + } + args+= (length +1); + size-= (length +1); + } + } + else if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) + { + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + restore_server_job_handle(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + restore_server_job_handle(data, server_job); + } + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + if (server_job->ignore_job == true) + { + restore_server_job_handle(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; ++x) + { + for (gearman_server_job_st *server_job= Server->job_hash[x]; server_job != NULL; server_job= server_job->next) + { + if (server_job->ignore_job == true) + { + restore_server_job_handle(data, server_job); + } + } + } + } + data.vec_append_printf(TEXT_END); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_RESTORE_ARGUMENTS); + } + } + else if (strcasecmp("show", packet->arg[0]) == 0) + { + if (packet->argc >= 4 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("job", packet->arg[2]) == 0) + { + gearman_server_job_st *server_job= gearman_server_job_get_by_unique(Server, packet->arg[3], strlen(packet->arg[3]), NULL); + if (server_job != NULL) + { + show_server_job_unique(data, server_job); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + } + else if (packet->argc >= 3 and strcasecmp("job", packet->arg[1]) == 0) + { + gearman_server_job_st *server_job= gearman_server_job_get(Server, packet->arg[2], strlen(packet->arg[2]), NULL); + if (server_job != NULL) + { + show_server_job_handle(data, server_job); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + } + else if (packet->argc >= 3 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("jobs", packet->arg[2]) == 0) + { + if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) + { + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_job_st *server_job= gearman_server_job_get_by_unique(Server, args, length, NULL); + if (server_job != NULL) + { + show_server_job_unique(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } + } + args+= (length +1); + size-= (length +1); + } + } + else if (packet->argc >= 5 and strcasecmp("-", packet->arg[4]) != 0) + { + char *args= packet->arg[4]; + int64_t size= strlen(packet->arg[4]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + show_server_job_unique(data, server_job); + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + show_server_job_unique(data, server_job); + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + show_server_job_unique(data, server_job); + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; x++) + { + for (gearman_server_job_st* server_job= Server->unique_hash[x]; server_job != NULL; server_job= server_job->unique_next) + { + show_server_job_unique(data, server_job); + } + } + } + data.vec_append_printf(TEXT_END); + } + else if (packet->argc >= 2 and strcasecmp("jobs", packet->arg[1]) == 0) + { + if (packet->argc >= 3 and strcasecmp("-", packet->arg[2]) != 0) + { + char *args= packet->arg[2]; + int64_t size= strlen(packet->arg[2]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_job_st *server_job= gearman_server_job_get(Server, args, length, NULL); + if (server_job != NULL) + { + show_server_job_handle(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } + } + args+= (length +1); + size-= (length +1); + } + } + else if (packet->argc >= 4 and strcasecmp("-", packet->arg[3]) != 0) + { + char *args= packet->arg[3]; + int64_t size= strlen(packet->arg[3]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL and server_function->job_count > 0) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= gearman_job_priority_t(int(priority) +1)) + { + for (gearman_server_job_st *server_job= server_function->job_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + show_server_job_handle(data, server_job); + } + for (gearman_server_job_st *server_job= server_function->job_bg_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + show_server_job_handle(data, server_job); + } + for (gearman_server_job_st *server_job= server_function->job_epoch_list[priority]; server_job != NULL; server_job= server_job->function_next) + { + show_server_job_handle(data, server_job); + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; ++x) + { + for (gearman_server_job_st *server_job= Server->job_hash[x]; server_job != NULL; server_job= server_job->next) + { + show_server_job_handle(data, server_job); + } + } + } + data.vec_append_printf(TEXT_END); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_SHOW_ARGUMENTS); + } + } + else if (strcasecmp("config", packet->arg[0]) == 0) + { + struct Options_st options; + struct Options_use_st options_use; + if (packet->argc >= 3 and strcasecmp("function", packet->arg[1]) == 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, packet->arg[2], strlen(packet->arg[2]), false); + if (server_function != NULL) + { + if (packet->argc >= 4 and strcmp("-", packet->arg[3]) != 0) + { + parse_options(packet->arg[3], options, options_use); + apply_options(server_function, options, options_use); + data.vec_printf(TEXT_SUCCESS); + } + else + { + print_options(data, server_function); + } + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_FUNCTION); + } + } + else if (packet->argc >= 2 and strcasecmp("functions", packet->arg[1]) == 0) + { + bool parsed= false; + if (packet->argc >= 3 and strcmp("-", packet->arg[2]) != 0) + { + char *args= packet->arg[2]; + int64_t size= strlen(packet->arg[2]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL) + { + if (packet->argc >= 4 and strcmp("-", packet->arg[3]) != 0) + { + if (parsed == false) + { + parse_options(packet->arg[3], options, options_use); + parsed= true; + } + apply_options(server_function, options, options_use); + data.vec_append_printf("%.*s\t%s", server_function->function_name_size, server_function->function_name, TEXT_SUCCESS); + } + else + { + print_options(data, server_function); + } + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_FUNCTION); + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (gearman_server_function_st *server_function= Server->function_hash[x]; server_function != NULL; server_function= server_function->next) + { + if (packet->argc >= 4 and strcmp("-", packet->arg[3]) != 0) + { + if (parsed == false) + { + parse_options(packet->arg[3], options, options_use); + parsed= true; + } + apply_options(server_function, options, options_use); + data.vec_append_printf("%.*s\t%s", server_function->function_name_size, server_function->function_name, TEXT_SUCCESS); + } + else + { + print_options(data, server_function); + } + } + } + } + data.vec_append_printf(TEXT_END); + } + else if (packet->argc >= 2 and strcasecmp("server", packet->arg[1]) == 0) + { + if (packet->argc >= 3 and strcmp("-", packet->arg[2]) != 0) + { + parse_options(packet->arg[2], options, options_use); + apply_options(NULL, options, options_use); + data.vec_printf(TEXT_SUCCESS); + } + else + { + print_options(data, NULL); + } + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_CONFIG_ARGUMENTS); + } + } + else if (strcasecmp("create", packet->arg[0]) == 0) + { + if (packet->argc >= 3 and strcasecmp("function", packet->arg[1]) == 0) + { + gearman_server_function_st* server_function= gearman_server_function_get(Server, packet->arg[2], strlen(packet->arg[2])); + if (server_function != NULL) + { + data.vec_printf(TEXT_SUCCESS); + } + else + { + data.vec_printf(TEXT_ERROR_CREATE_FUNCTION); + } + } + else if (packet->argc >= 3 and strcasecmp("functions", packet->arg[1]) == 0) + { + char *args= packet->arg[2]; + int64_t size= strlen(packet->arg[2]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st* server_function= gearman_server_function_get(Server, args, length); + if (server_function != NULL) + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_SUCCESS); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_CREATE_FUNCTION); + } + } + args+= (length +1); + size-= (length +1); + } + data.vec_append_printf(TEXT_END); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_CREATE_ARGUMENTS); + } + } + else if (strcasecmp("drop", packet->arg[0]) == 0) + { + if (packet->argc >= 3 and strcasecmp("function", packet->arg[1]) == 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, packet->arg[2], strlen(packet->arg[2]), false); + if (server_function != NULL) + { + if (server_function->worker_count == 0 && server_function->job_running == 0) + { + free_server_function_jobs(server_function); + gearman_server_function_free(Server, server_function); + data.vec_printf(TEXT_SUCCESS); + } + else + { + data.vec_printf(TEXT_ERROR_FUNCTION_HAS_WORKER); + } + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_FUNCTION); + } + } + else if (packet->argc >= 2 and strcasecmp("functions", packet->arg[1]) == 0) + { + if (packet->argc >= 3 and strcmp("-", packet->arg[2]) != 0) + { + char *args= packet->arg[2]; + int64_t size= strlen(packet->arg[2]); + while (size > 0) + { + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) + { + gearman_server_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL) + { + if (server_function->worker_count == 0 && server_function->job_running == 0) + { + free_server_function_jobs(server_function); + gearman_server_function_free(Server, server_function); + data.vec_append_printf("%.*s\t%s", server_function->function_name_size, server_function->function_name, TEXT_SUCCESS); + } + else + { + data.vec_append_printf("%.*s\t%s", server_function->function_name_size, server_function->function_name, TEXT_ERROR_FUNCTION_HAS_WORKER); + } + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_FUNCTION); + } + } + args+= (length +1); + size-= (length +1); + } + } + else + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (gearman_server_function_st *server_function= Server->function_hash[x]; server_function != NULL; server_function= server_function->next) + { + if (server_function->worker_count == 0 && server_function->job_running == 0) + { + free_server_function_jobs(server_function); + gearman_server_function_free(Server, server_function); + data.vec_append_printf("%.*s\t%s", server_function->function_name_size, server_function->function_name, TEXT_SUCCESS); + } + } + } } + data.vec_append_printf(TEXT_END); } else { - // drop - data.vec_printf(TEXT_ERROR_ARGS, (int)packet->arg_size[0], (char *)(packet->arg[0])); + data.vec_printf(TEXT_ERROR_UNKNOWN_DROP_ARGUMENTS); } } else if (strcasecmp("maxqueue", (char *)(packet->arg[0])) == 0) @@ -316,7 +1624,7 @@ (memcmp(packet->arg[1], function->function_name, function->function_name_size) == 0)) { gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "Applying queue limits to %s", function->function_name); - memcpy(function->max_queue_size, max_queue_size, sizeof(uint32_t) * GEARMAN_JOB_PRIORITY_MAX); + memcpy(function->options.max_queue_size, max_queue_size, sizeof(uint32_t) * GEARMAN_JOB_PRIORITY_MAX); } } } --- tests/libgearman-1.0/protocol.cc 2014-02-12 08:05:28.000000000 +0800 +++ tests/libgearman-1.0/protocol.cc 2014-08-02 20:22:29.445297135 +0800 @@ -92,6 +92,10 @@ ASSERT_EQ(38, int(GEARMAN_COMMAND_SUBMIT_REDUCE_JOB_BACKGROUND)); ASSERT_EQ(39, int(GEARMAN_COMMAND_GRAB_JOB_ALL)); ASSERT_EQ(40, int(GEARMAN_COMMAND_JOB_ASSIGN_ALL)); + ASSERT_EQ(41, int(GEARMAN_COMMAND_GET_STATUS_UNIQUE)); + ASSERT_EQ(42, int(GEARMAN_COMMAND_STATUS_RES_UNIQUE)); + ASSERT_EQ(43, int(GEARMAN_COMMAND_SUBMIT_JOB_HIGH_EPOCH)); + ASSERT_EQ(44, int(GEARMAN_COMMAND_SUBMIT_JOB_LOW_EPOCH)); return TEST_SUCCESS; } --- util/instance.cc 2014-02-12 08:05:28.000000000 +0800 +++ util/instance.cc 2014-09-06 16:28:27.021927920 +0800 @@ -125,7 +125,7 @@ SSL_load_error_strings(); SSL_library_init(); - if ((_ctx_ssl= SSL_CTX_new(TLSv1_client_method())) == NULL) + if ((_ctx_ssl= SSL_CTX_new(SSLv23_client_method())) == NULL) { _last_error= "SSL_CTX_new error"; return false; @@ -154,7 +154,15 @@ _last_error= message.str(); return false; } -#endif // defined(HAVE_CYASSL) && HAVE_CYASSL + + if (SSL_CTX_check_private_key(_ctx_ssl) != SSL_SUCCESS) + { + std::stringstream message; + message << "Error check private key."; + _last_error= message.str(); + return false; + } +#endif // defined(HAVE_SSL) && HAVE_SSL return true; } @@ -273,6 +281,8 @@ _last_error= "SSL_set_fd() failed"; return false; } + + SSL_set_connect_state(_ssl); } #endif @@ -282,7 +292,11 @@ #if defined(HAVE_SSL) && HAVE_SSL if (_ssl) { +# if defined(HAVE_CYASSL) && HAVE_CYASSL + write_size= CyaSSL_send(_ssl, (const void*)packet, int(packet_length), MSG_NOSIGNAL); +# else write_size= SSL_write(_ssl, (const void*)packet, int(packet_length)); +# endif int ssl_error; switch ((ssl_error= SSL_get_error(_ssl, int(write_size)))) { @@ -315,6 +329,12 @@ case SSL_ERROR_SSL: default: { +# if defined(HAVE_OPENSSL) && HAVE_OPENSSL + if (ERR_peek_last_error()) + { + ssl_error= ERR_peek_last_error(); + } +# endif char cyassl_error_buffer[SSL_ERROR_SIZE]= { 0 }; ERR_error_string_n(ssl_error, cyassl_error_buffer, sizeof(cyassl_error_buffer)); _last_error= cyassl_error_buffer; @@ -355,15 +375,20 @@ if (operation->has_response()) { ssize_t read_size; + char buffer[BUFSIZ]; + bool _more_to_read= true; do { - char buffer[BUFSIZ]; #if defined(HAVE_SSL) && HAVE_SSL if (_ssl) { { +# if defined(HAVE_CYASSL) && HAVE_CYASSL + read_size= CyaSSL_recv(_ssl, (void *)buffer, sizeof(buffer), MSG_NOSIGNAL); +# else read_size= SSL_read(_ssl, (void *)buffer, sizeof(buffer)); +# endif int ssl_error; switch ((ssl_error= SSL_get_error(_ssl, int(read_size)))) { @@ -398,6 +423,12 @@ case SSL_ERROR_SSL: default: { +# if defined(HAVE_OPENSSL) && HAVE_OPENSSL + if (ERR_peek_last_error()) + { + ssl_error= ERR_peek_last_error(); + } +# endif char cyassl_error_buffer[SSL_ERROR_SIZE]= { 0 }; ERR_error_string_n(ssl_error, cyassl_error_buffer, sizeof(cyassl_error_buffer)); _last_error= cyassl_error_buffer; @@ -413,7 +444,11 @@ read_size= ::recv(_sockfd, buffer, sizeof(buffer), 0); } - if (read_size == 0) + if (read_size > 0) + { + operation->push(buffer, static_cast(read_size)); + } + else if (read_size == 0 and _more_to_read == true) { _last_error.clear(); _last_error+= "Socket was shutdown while reading from "; @@ -433,9 +468,7 @@ return false; } - operation->push(buffer, static_cast(read_size)); - - } while (more_to_read()); + } while ((_more_to_read= more_to_read()) or read_size == sizeof(buffer)); } // end has_response state= FINISHED;