--- bin/gearadmin.cc 2014-02-12 08:05:28.000000000 +0800 +++ bin/gearadmin.cc 2014-11-18 17:14:13.644142423 +0800 @@ -136,13 +136,39 @@ ("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 or show the server's job_retries, job_retries_warn, job_count_max, job_count_max_interval, job_worker_ratio_max, job_worker_ratio_max_interval, job_worker_ratio_min, job_worker_ratio_min_interval, worker_count_max, worker_count_max_interval, worker_count_min, worker_count_min_interval, worker_wakeup, max_queue_size_0, max_queue_size_1, max_queue_size_2, job_retries_action, job_retries_warn_action, job_count_max_action, job_worker_ratio_max_action, job_worker_ratio_min_action, worker_count_max_action, worker_count_min_action, worker_failed_action.") + ("config-function", boost::program_options::value >()->multitoken(), "Config or show the function's job_retries, job_retries_warn, job_count_max, job_count_max_interval, job_worker_ratio_max, job_worker_ratio_max_interval, job_worker_ratio_min, job_worker_ratio_min_interval, worker_count_max, worker_count_max_interval, worker_count_min, worker_count_min_interval, worker_wakeup, max_queue_size_0, max_queue_size_1, max_queue_size_2, job_retries_action, job_retries_warn_action, job_count_max_action, job_worker_ratio_max_action, job_worker_ratio_min_action, worker_count_max_action, worker_count_min_action, worker_failed_action.") + ("config-functions", boost::program_options::value >()->multitoken()->zero_tokens(), "Config or show the functions's job_retries, job_retries_warn, job_count_max, job_count_max_interval, job_worker_ratio_max, job_worker_ratio_max_interval, job_worker_ratio_min, job_worker_ratio_min_interval, worker_count_max, worker_count_max_interval, worker_count_min, worker_count_min_interval, worker_wakeup, max_queue_size_0, max_queue_size_1, max_queue_size_2, job_retries_action, job_retries_warn_action, job_count_max_action, job_worker_ratio_max_action, job_worker_ratio_min_action, worker_count_max_action, worker_count_min_action, worker_failed_action.") + ("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 ',') .") + ("skip-unique-job", boost::program_options::value(), "Skip a given unique job in the server's queue") + ("skip-job", boost::program_options::value(), "Skip a given handle job in the server's queue") + ("skip-unique-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Skip unique jobs in the server's queue. ARG can be uniques (separated by ',' . '-' if there are functions but no unique) and functions (separated by ',') .") + ("skip-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Skip handle jobs in the server's queue. ARG can be handles (separated by ',' . '-' if there are functions but no handle) and functions (separated by ',') .") + ("turnback-unique-job", boost::program_options::value(), "Turn back a given skipped unique job from the server's queue") + ("turnback-job", boost::program_options::value(), "Turn back a given skipped handle job from the server's queue") + ("turnback-unique-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Turn back skipped unique jobs from the server's queue. ARG can be uniques (separated by ',' . '-' if there are functions but no unique) and functions (separated by ',') .") + ("turnback-jobs", boost::program_options::value >()->multitoken()->zero_tokens(), "Turn back skipped handle jobs from the server's queue. 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 +202,42 @@ } 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("skip-unique-job") == 0 and + vm.count("skip-job") == 0 and + vm.count("skip-unique-jobs") == 0 and + vm.count("skip-jobs") == 0 and + vm.count("turnback-unique-job") == 0 and + vm.count("turnback-job") == 0 and + vm.count("turnback-unique-jobs") == 0 and + vm.count("turnback-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 +251,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 +276,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 +292,228 @@ 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("skip-unique-job")) + { + std::string execute(util_literal_param("skip unique job ")); + execute.append(vm["skip-unique-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("skip-job")) + { + std::string execute(util_literal_param("skip job ")); + execute.append(vm["skip-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("skip-unique-jobs")) + { + std::string execute(util_literal_param("skip unique jobs")); + std::vector jobs_argv= vm["skip-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("skip-jobs")) + { + std::string execute(util_literal_param("skip jobs")); + std::vector jobs_argv= vm["skip-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("turnback-unique-job")) + { + std::string execute(util_literal_param("turnback unique job ")); + execute.append(vm["turnback-unique-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("turnback-job")) + { + std::string execute(util_literal_param("turnback job ")); + execute.append(vm["turnback-job"].as()); + execute.append("\r\n"); + instance.push(new util::Operation(execute.c_str(), execute.size())); + } + + if (vm.count("turnback-unique-jobs")) + { + std::string execute(util_literal_param("turnback unique jobs")); + std::vector jobs_argv= vm["turnback-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("turnback-jobs")) + { + std::string execute(util_literal_param("turnback jobs")); + std::vector jobs_argv= vm["turnback-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 +524,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 +543,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-10-20 09:42:17.859728545 +0800 @@ -107,8 +107,8 @@ int backlog; rlim_t fds= 0; - uint32_t job_retries; - uint32_t worker_wakeup; + + struct gearman_server_options_st options; std::string host; std::string user; @@ -140,6 +140,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 +155,52 @@ ("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-action", boost::program_options::value(&(options.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-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-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(&(options.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(&(options.job_retries_warn_action))->default_value(""), + "Program to be run when the job's attempts reaches job-retries-warn. Default('') means no action.") + + ("job-worker-ratio-max", boost::program_options::value(&(options.job_worker_ratio_max))->default_value(0), + "MAX Ratio of job / worker per function before the job server gives a warning about it. Default(0) means no action.") + + ("job-worker-ratio-max-action", boost::program_options::value(&(options.job_worker_ratio_max_action))->default_value(""), + "Program to be run when Ratio of job / worker per function is more than job-worker-ratio-max. Default('') means no action.") + + ("job-worker-ratio-max-interval", boost::program_options::value(&(options.job_worker_ratio_max_interval))->default_value(0), + "Interval between actions of testing and warning about job-worker-ratio-max. Default(0) means no action.") + + ("job-worker-ratio-min", boost::program_options::value(&(options.job_worker_ratio_min))->default_value(0), + "MIN Ratio of job / worker per function before the job server gives a warning about it. Default(0) means no action.") + + ("job-worker-ratio-min-action", boost::program_options::value(&(options.job_worker_ratio_min_action))->default_value(""), + "Program to be run when Ratio of job / worker per function is less than job-worker-ratio-min. Default('') means no action.") + + ("job-worker-ratio-min-interval", boost::program_options::value(&(options.job_worker_ratio_min_interval))->default_value(0), + "Interval between actions of testing and warning about job-worker-ratio-min. Default(0) means no action.") ("keepalive", boost::program_options::bool_switch(&opt_keepalive)->default_value(false), "Enable keepalive on sockets.") @@ -178,27 +220,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 +254,29 @@ "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-max", boost::program_options::value(&(options.worker_count_max))->default_value(0), + "MAX Number of workers per function before the job server gives a warning about it. Default(0) means no action.") + + ("worker-count-max-action", boost::program_options::value(&(options.worker_count_max_action))->default_value(""), + "Program to be run when Number of workers per function is more than worker-count-max. Default('') means no action.") + + ("worker-count-max-interval", boost::program_options::value(&(options.worker_count_max_interval))->default_value(0), + "Interval between actions of testing and warning about worker-count-max. Default(0) means no action.") + + ("worker-count-min", boost::program_options::value(&(options.worker_count_min))->default_value(0), + "MIN Number of workers per function before the job server gives a warning about it. Default(0) means no action.") + + ("worker-count-min-action", boost::program_options::value(&(options.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-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-failed-action", boost::program_options::value(&(options.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 +457,11 @@ 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); 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-10-07 03:15:48.178968539 +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,44 @@ { while (con->worker_list != NULL) { + if (con->is_dead == true) + { + gearman_server_function_st *function= con->worker_list->function; + if (function->options.worker_failed_action.empty() == true) + { + uint32_t comma= (con->_function_names_size == 0) ? 0 : 1; + 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); + } + } + else + { + gearman_server_notify_worker_failed_1(Server, con, function); + } + } 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_2(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-09-06 21:26:51.925270891 +0800 @@ -147,6 +147,14 @@ 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_JOB_NOT_SKIPPED: + return "JOB_NOT_SKIPPED"; + case GEARMAND_JOB_SKIPPED: + return "JOB_SKIPPED"; 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-09-06 21:26:10.498606014 +0800 @@ -93,6 +93,10 @@ GEARMAND_TIMEOUT, GEARMAND_ARGUMENT_TOO_LARGE, GEARMAND_INVALID_ARGUMENT, + GEARMAND_JOB_NOT_CANCELED, + GEARMAND_JOB_CANCELED, + GEARMAND_JOB_NOT_SKIPPED, + GEARMAND_JOB_SKIPPED, 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-12-23 11:50:34.747246965 +0800 @@ -46,6 +46,8 @@ #include #include +#include +#include /* * Public definitions @@ -80,19 +82,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 +99,29 @@ 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); + 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 +136,11 @@ } } + if (auto_create == false) + { + return NULL; + } + return gearman_server_function_create(server, function_name, function_name_size, function_hash); } @@ -144,3 +154,583 @@ delete function; } #pragma GCC diagnostic pop + + +void gearman_server_notify_job_retries(gearman_server_st *server, gearman_server_job_st *job) +{ + std::string &job_retries_action= (job->function->options.job_retries_action.empty() == true) ? server->options.job_retries_action : job->function->options.job_retries_action; + if (job_retries_action.empty() == true) + { + 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]= (char *)(job_retries_action.c_str()); + 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(argv[0], 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) +{ + std::string &job_retries_warn_action= (job->function->options.job_retries_warn_action.empty() == true) ? server->options.job_retries_warn_action : job->function->options.job_retries_warn_action; + if (job_retries_warn_action.empty() == true) + { + 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]= (char *)(job_retries_warn_action.c_str()); + 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(argv[0], 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; + std::string &job_count_max_action= (function->options.job_count_max_action.empty() == true) ? server->options.job_count_max_action : function->options.job_count_max_action; + if (job_count_max == 0 || job_count_max >= function->job_count || job_count_max_action.empty() == true) + { + 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]= (char *)(job_count_max_action.c_str()); + 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(argv[0], 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_job_worker_ratio_max(gearman_server_st *server, gearman_server_function_st *function) +{ + uint32_t job_worker_ratio= (function->worker_count == 0) ? function->job_count : round((double)(function->job_count) / (double)(function->worker_count)); + uint32_t job_worker_ratio_max= (function->options.job_worker_ratio_max == 0) ? server->options.job_worker_ratio_max : function->options.job_worker_ratio_max; + std::string &job_worker_ratio_max_action= (function->options.job_worker_ratio_max_action.empty() == true) ? server->options.job_worker_ratio_max_action : function->options.job_worker_ratio_max_action; + if (job_worker_ratio_max == 0 || job_worker_ratio_max >= job_worker_ratio || job_worker_ratio_max_action.empty() == true) + { + return; + } + + char _job_worker_ratio[11]; + char _job_worker_ratio_max[11]; + sprintf(_job_worker_ratio, "%u", job_worker_ratio); + sprintf(_job_worker_ratio_max, "%u", job_worker_ratio_max); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[5]; + argv[0]= (char *)(job_worker_ratio_max_action.c_str()); + argv[1]= function->function_name; + argv[2]= _job_worker_ratio_max; + argv[3]= _job_worker_ratio; + argv[4]= 0; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]); + execv(argv[0], 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_job_worker_ratio_min(gearman_server_st *server, gearman_server_function_st *function) +{ + uint32_t job_worker_ratio= (function->worker_count == 0) ? function->job_count : round((double)(function->job_count) / (double)(function->worker_count)); + uint32_t job_worker_ratio_min= (function->options.job_worker_ratio_min == 0) ? server->options.job_worker_ratio_min : function->options.job_worker_ratio_min; + std::string &job_worker_ratio_min_action= (function->options.job_worker_ratio_min_action.empty() == true) ? server->options.job_worker_ratio_min_action : function->options.job_worker_ratio_min_action; + if (job_worker_ratio_min == 0 || job_worker_ratio_min <= job_worker_ratio || job_worker_ratio_min_action.empty() == true) + { + return; + } + + char _job_worker_ratio[11]; + char _job_worker_ratio_min[11]; + sprintf(_job_worker_ratio, "%u", job_worker_ratio); + sprintf(_job_worker_ratio_min, "%u", job_worker_ratio_min); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[5]; + argv[0]= (char *)(job_worker_ratio_min_action.c_str()); + argv[1]= function->function_name; + argv[2]= _job_worker_ratio_min; + argv[3]= _job_worker_ratio; + argv[4]= 0; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s %s %s %s", argv[0], argv[1], argv[2], argv[3]); + execv(argv[0], 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_max(gearman_server_st *server, gearman_server_function_st *function) +{ + uint32_t worker_count_max= (function->options.worker_count_max == 0) ? server->options.worker_count_max : function->options.worker_count_max; + std::string &worker_count_max_action= (function->options.worker_count_max_action.empty() == true) ? server->options.worker_count_max_action : function->options.worker_count_max_action; + if (worker_count_max == 0 || worker_count_max >= function->worker_count || worker_count_max_action.empty() == true) + { + return; + } + + char _worker_count[11]; + char _worker_count_max[11]; + sprintf(_worker_count_max, "%u", worker_count_max); + 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]= (char *)(worker_count_max_action.c_str()); + argv[1]= function->function_name; + argv[2]= _worker_count_max; + 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(argv[0], 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; + std::string &worker_count_min_action= (function->options.worker_count_min_action.empty() == true) ? server->options.worker_count_min_action : function->options.worker_count_min_action; + if (worker_count_min == 0 || worker_count_min <= function->worker_count || worker_count_min_action.empty() == true) + { + 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]= (char *)(worker_count_min_action.c_str()); + 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(argv[0], 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_1(gearman_server_st *server, gearman_server_con_st *con, gearman_server_function_st *function) +{ + std::string &worker_failed_action= (function->options.worker_failed_action.empty() == true) ? server->options.worker_failed_action : function->options.worker_failed_action; + if (worker_failed_action.empty() == true) + { + return; + } + + char _function_names_count[11]; + sprintf(_function_names_count, "%u", 1); + char _function_names[128]; + sprintf(_function_names, "%.*s", (int)(function->function_name_size), function->function_name); + + signal(SIGCHLD, SIG_IGN); + pid_t child_pid= fork(); + if (child_pid == 0) + { + char *argv[6]; + argv[0]= (char *)(worker_failed_action.c_str()); + argv[1]= (char *)(con->_host); + argv[2]= (char *)(con->_port); + argv[3]= _function_names_count; + argv[4]= _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(argv[0], 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_worker_failed_2(gearman_server_st *server, gearman_server_con_st *con) +{ + std::string &worker_failed_action= server->options.worker_failed_action; + if (worker_failed_action.empty() == true) + { + 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]= (char *)(worker_failed_action.c_str()); + 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(argv[0], 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 == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name); + if (function == NULL) + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (function= Server->function_hash[x]; function != NULL; function= function->next) + { + if (function->options.job_count_max_timer == NULL) + { + gearman_server_notify_job_count_max(Server, function); + } + } + } + } + else + { + gearman_server_notify_job_count_max(Server, function); + } +} + +static void _gearman_server_notify_job_worker_ratio_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 (job_worker_ratio_max, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name); + if (function == NULL) + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (function= Server->function_hash[x]; function != NULL; function= function->next) + { + if (function->options.job_worker_ratio_max_timer == NULL) + { + gearman_server_notify_job_worker_ratio_max(Server, function); + } + } + } + } + else + { + gearman_server_notify_job_worker_ratio_max(Server, function); + } +} + +static void _gearman_server_notify_job_worker_ratio_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 (job_worker_ratio_min, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name); + if (function == NULL) + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (function= Server->function_hash[x]; function != NULL; function= function->next) + { + if (function->options.job_worker_ratio_min_timer == NULL) + { + gearman_server_notify_job_worker_ratio_min(Server, function); + } + } + } + } + else + { + gearman_server_notify_job_worker_ratio_min(Server, function); + } +} + +static void _gearman_server_notify_worker_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 (worker_count_max, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name); + if (function == NULL) + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (function= Server->function_hash[x]; function != NULL; function= function->next) + { + if (function->options.worker_count_max_timer == NULL) + { + gearman_server_notify_worker_count_max(Server, function); + } + } + } + } + else + { + gearman_server_notify_worker_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 (worker_count_min, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name); + if (function == NULL) + { + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) + { + for (function= Server->function_hash[x]; function != NULL; function= function->next) + { + if (function->options.worker_count_min_timer == NULL) + { + gearman_server_notify_worker_count_min(Server, function); + } + } + } + } + else + { + gearman_server_notify_worker_count_min(Server, function); + } +} + +static bool _gearman_server_timer(const char *type, gearman_server_function_st *function, timer_t &timerid, uint32_t interval, uint32_t count, const std::string &action, void (*notify)(sigval_t)) +{ + if (interval == 0 or (function != NULL and (count == 0 or action.empty() == true))) + { + 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", + type, (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + 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", + type, (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + 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", + type, (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + 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", + type, (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + 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) +{ + timer_t &timerid= (function == NULL) ? server->options.job_count_max_timer : function->options.job_count_max_timer; + uint32_t interval= (function == NULL) ? server->options.job_count_max_interval : function->options.job_count_max_interval; + uint32_t count= (function == NULL or function->options.job_count_max == 0) ? server->options.job_count_max : function->options.job_count_max; + std::string &action= (function == NULL or function->options.job_count_max_action.empty() == true) ? server->options.job_count_max_action : function->options.job_count_max_action; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer config for (job_count_max, %.*s, %u, %u, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + interval, count, action.size(), action.c_str()); + return _gearman_server_timer("job_count_max", function, timerid, interval, count, action, _gearman_server_notify_job_count_max); +} + +bool gearman_server_timer_job_worker_ratio_max(gearman_server_st *server, gearman_server_function_st *function) +{ + timer_t &timerid= (function == NULL) ? server->options.job_worker_ratio_max_timer : function->options.job_worker_ratio_max_timer; + uint32_t interval= (function == NULL) ? server->options.job_worker_ratio_max_interval : function->options.job_worker_ratio_max_interval; + uint32_t count= (function == NULL or function->options.job_worker_ratio_max == 0) ? server->options.job_worker_ratio_max : function->options.job_worker_ratio_max; + std::string &action= (function == NULL or function->options.job_worker_ratio_max_action.empty() == true) ? server->options.job_worker_ratio_max_action : function->options.job_worker_ratio_max_action; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer config for (job_worker_ratio_max, %.*s, %u, %u, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + interval, count, action.size(), action.c_str()); + return _gearman_server_timer("job_worker_ratio_max", function, timerid, interval, count, action, _gearman_server_notify_job_worker_ratio_max); +} + +bool gearman_server_timer_job_worker_ratio_min(gearman_server_st *server, gearman_server_function_st *function) +{ + timer_t &timerid= (function == NULL) ? server->options.job_worker_ratio_min_timer : function->options.job_worker_ratio_min_timer; + uint32_t interval= (function == NULL) ? server->options.job_worker_ratio_min_interval : function->options.job_worker_ratio_min_interval; + uint32_t count= (function == NULL or function->options.job_worker_ratio_min == 0) ? server->options.job_worker_ratio_min : function->options.job_worker_ratio_min; + std::string &action= (function == NULL or function->options.job_worker_ratio_min_action.empty() == true) ? server->options.job_worker_ratio_min_action : function->options.job_worker_ratio_min_action; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer config for (job_worker_ratio_min, %.*s, %u, %u, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + interval, count, action.size(), action.c_str()); + return _gearman_server_timer("job_worker_ratio_min", function, timerid, interval, count, action, _gearman_server_notify_job_worker_ratio_min); +} + +bool gearman_server_timer_worker_count_max(gearman_server_st *server, gearman_server_function_st *function) +{ + timer_t &timerid= (function == NULL) ? server->options.worker_count_max_timer : function->options.worker_count_max_timer; + uint32_t interval= (function == NULL) ? server->options.worker_count_max_interval : function->options.worker_count_max_interval; + uint32_t count= (function == NULL or function->options.worker_count_max == 0) ? server->options.worker_count_max : function->options.worker_count_max; + std::string &action= (function == NULL or function->options.worker_count_max_action.empty() == true) ? server->options.worker_count_max_action : function->options.worker_count_max_action; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer config for (worker_count_max, %.*s, %u, %u, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + interval, count, action.size(), action.c_str()); + return _gearman_server_timer("worker_count_max", function, timerid, interval, count, action, _gearman_server_notify_worker_count_max); +} + +bool gearman_server_timer_worker_count_min(gearman_server_st *server, gearman_server_function_st *function) +{ + timer_t &timerid= (function == NULL) ? server->options.worker_count_min_timer : function->options.worker_count_min_timer; + uint32_t interval= (function == NULL) ? server->options.worker_count_min_interval : function->options.worker_count_min_interval; + uint32_t count= (function == NULL or function->options.worker_count_min == 0) ? server->options.worker_count_min : function->options.worker_count_min; + std::string &action= (function == NULL or function->options.worker_count_min_action.empty() == true) ? server->options.worker_count_min_action : function->options.worker_count_min_action; + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "timer config for (worker_count_min, %.*s, %u, %u, %.*s)", + (function == NULL) ? 3 : function->function_name_size, + (function == NULL) ? "ALL" : function->function_name, + interval, count, action.size(), action.c_str()); + return _gearman_server_timer("worker_count_min", function, timerid, interval, count, action, _gearman_server_notify_worker_count_min); +} --- libgearman-server/function.h 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/function.h 2014-12-10 19:17:42.145749391 +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,74 @@ 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 more than worker_count_max + */ +GEARMAN_API +void gearman_server_notify_worker_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_1(gearman_server_st *server, gearman_server_con_st *con, gearman_server_function_st *function); +GEARMAN_API +void gearman_server_notify_worker_failed_2(gearman_server_st *server, gearman_server_con_st *con); + +/** + * Create / Set / Delete timer for job_count_max + */ +GEARMAN_API +bool gearman_server_timer_job_count_max(gearman_server_st *server, gearman_server_function_st *function); + +/** + * Create / Set / Delete timer for job_worker_ratio_max + */ +GEARMAN_API +bool gearman_server_timer_job_worker_ratio_max(gearman_server_st *server, gearman_server_function_st *function); + +/** + * Create / Set / Delete timer for job_worker_ratio_min + */ +GEARMAN_API +bool gearman_server_timer_job_worker_ratio_min(gearman_server_st *server, gearman_server_function_st *function); + +/** + * Create / Set / Delete timer for worker_count_max + */ +GEARMAN_API +bool gearman_server_timer_worker_count_max(gearman_server_st *server, gearman_server_function_st *function); + +/** + * Create / Set / Delete 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-12-20 16:20:17.848272666 +0800 @@ -114,11 +114,10 @@ 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, + const struct gearman_server_options_st &options); static void gearmand_set_log_fn(gearmand_st *gearmand, gearmand_log_fn *function, void *context, const gearmand_verbose_t verbose); @@ -175,6 +174,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 +230,12 @@ 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, + const struct gearman_server_options_st &options) { assert(_global_gearmand == NULL); if (_global_gearmand) @@ -249,9 +254,7 @@ 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) == false) { delete gearmand; _global_gearmand= NULL; @@ -1195,21 +1198,19 @@ } 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, + const struct gearman_server_options_st &options) { 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 +1224,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 +1277,28 @@ return false; } + server.options= options; + if (options.job_count_max_interval != 0) + { + gearman_server_timer_job_count_max(&server, NULL); + } + if (options.job_worker_ratio_max_interval != 0) + { + gearman_server_timer_job_worker_ratio_max(&server, NULL); + } + if (options.job_worker_ratio_min_interval != 0) + { + gearman_server_timer_job_worker_ratio_min(&server, NULL); + } + if (options.worker_count_max_interval != 0) + { + gearman_server_timer_worker_count_max(&server, NULL); + } + if (options.worker_count_min_interval != 0) + { + gearman_server_timer_worker_count_min(&server, NULL); + } + 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-12-19 18:03:54.475303534 +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,215 @@ 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); - server_job->ignore_job= true; - server_job->job_queued= false; + return GEARMAND_SUCCESS; +} - 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)); +} + +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)); +} + +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)); +} + +gearmand_error_t _gearman_server_job_skip(gearman_server_job_st *server_job) +{ + if (server_job == NULL) + { + return GEARMAND_NO_JOBS; + } + else if (server_job->skip_job == true) + { + return GEARMAND_JOB_SKIPPED; + } + + server_job->skip_job= true; + return GEARMAND_SUCCESS; +} + +gearmand_error_t gearman_server_job_skip(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "skip: %.*s", job_handle_length, job_handle); + return _gearman_server_job_skip(gearman_server_job_get(&server, job_handle, job_handle_length, NULL)); +} + +gearmand_error_t gearman_server_job_skip_by_unique(gearman_server_st& server, + const char *unique, + const size_t unique_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "skip: %.*s", unique_length, unique); + return _gearman_server_job_skip(gearman_server_job_get_by_unique(&server, unique, unique_length, NULL)); +} + +gearmand_error_t _gearman_server_job_turnback(gearman_server_job_st *server_job) +{ + if (server_job == NULL) + { + return GEARMAND_NO_JOBS; + } + else if (server_job->skip_job == false) + { + return GEARMAND_JOB_NOT_SKIPPED; + } + + gearman_server_job_wakeup_workers(server_job); + server_job->skip_job= false; + return GEARMAND_SUCCESS; +} + +gearmand_error_t gearman_server_job_turnback(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "skip: %.*s", job_handle_length, job_handle); + return _gearman_server_job_turnback(gearman_server_job_get(&server, job_handle, job_handle_length, NULL)); +} + +gearmand_error_t gearman_server_job_turnback_by_unique(gearman_server_st& server, + const char *unique, + const size_t unique_length) +{ + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "skip: %.*s", unique_length, unique); + return _gearman_server_job_turnback(gearman_server_job_get_by_unique(&server, unique, unique_length, NULL)); } gearman_server_job_st * gearman_server_job_peek(gearman_server_con_st *server_con) @@ -315,35 +471,44 @@ 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; + for (server_job= server_worker->function->job_epoch_list[priority]; + server_job != NULL and server_job->skip_job; + server_job= server_job->function_next); + if (server_job != NULL and server_job->when > time(NULL)) + { + server_job= NULL; + } } - - if (server_job != NULL) + if (server_job == NULL) + { + for (server_job= server_worker->function->job_list[priority]; + server_job != NULL and server_job->skip_job; + server_job= server_job->function_next); + } + if (server_job == NULL) { + for (server_job= server_worker->function->job_bg_list[priority]; + server_job != NULL and server_job->skip_job; + server_job= server_job->function_next); + } + 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 +517,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,51 +542,96 @@ } } + 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; + for (server_job= server_worker->function->job_epoch_list[priority]; + server_job != NULL and server_job->skip_job; + server_job= server_job->function_next); + if (server_job != NULL) + { + if (server_job->when > time(NULL)) + { + server_job= NULL; + continue; + } + if (server_job->function->job_epoch_list[priority] == server_job) + { + server_job->function->job_epoch_list[priority]= server_job->function_next; + } + if (server_job->function->job_epoch_end[priority] == server_job) + { + server_job->function->job_epoch_end[priority]= server_job->function_prev; + } + 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; + for (server_job= server_worker->function->job_list[priority]; + server_job != NULL and server_job->skip_job; + server_job= server_job->function_next); + if (server_job != NULL) + { + if (server_job->function->job_list[priority] == server_job) + { + server_job->function->job_list[priority]= server_job->function_next; + } + if (server_job->function->job_end[priority] == server_job) + { + server_job->function->job_end[priority]= server_job->function_prev; + } + 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; + for (server_job= server_worker->function->job_bg_list[priority]; + server_job != NULL and server_job->skip_job; + server_job= server_job->function_next); + if (server_job != NULL) + { + if (server_job->function->job_bg_list[priority] == server_job) + { + server_job->function->job_bg_list[priority]= server_job->function_next; + } + if (server_job->function->job_bg_end[priority] == server_job) + { + server_job->function->job_bg_end[priority]= server_job->function_prev; + } + 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++; + if (server_job->function_prev != NULL) + { + server_job->function_prev->function_next= server_job->function_next; + } + if (server_job->function_next != NULL) + { + server_job->function_next->function_prev= server_job->function_prev; + } + if (server_job->ignore_job) { gearman_server_job_free(server_job); @@ -537,6 +746,7 @@ } } + server_job->skip_job= false; server_job->ignore_job= false; server_job->job_queued= false; server_job->retries= 0; @@ -555,6 +765,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-10-04 21:20:43.293395025 +0800 @@ -78,11 +78,66 @@ 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); + +gearmand_error_t _gearman_server_job_skip(gearman_server_job_st *server_job); + +GEARMAN_API +gearmand_error_t gearman_server_job_skip(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + +GEARMAN_API +gearmand_error_t gearman_server_job_skip_by_unique(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + +gearmand_error_t _gearman_server_job_turnback(gearman_server_job_st *server_job); + +GEARMAN_API +gearmand_error_t gearman_server_job_turnback(gearman_server_st& server, + const char *job_handle, + const size_t job_handle_length); + +GEARMAN_API +gearmand_error_t gearman_server_job_turnback_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-10-03 21:11:21.099624066 +0800 @@ -107,13 +107,12 @@ 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, + const struct gearman_server_options_st &options); /** * 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-12-22 13:38:52.840101467 +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) { @@ -337,13 +341,59 @@ } } +void gearman_server_job_wakeup_workers(gearman_server_job_st *job) +{ + 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 + { + if (worker->con->is_sleeping && ! (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; + noop_sent++; + } + } + + worker= worker->function_next; + } + while (worker != job->function->worker_list && job->function->job_count > noop_sent && (worker_wakeup == 0 || worker_wakeup > noop_sent)); + + job->function->worker_list= worker; +} + 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; + std::string &job_retries_warn_action= (job->function->options.job_retries_warn_action.empty() == true) ? Server->options.job_retries_warn_action : job->function->options.job_retries_warn_action; + if (job_retries_warn != 0 && job_retries_warn <= job->retries && job_retries_warn_action.empty() == false) + { + 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; + std::string &job_retries_action= (job->function->options.job_retries_action.empty() == true) ? Server->options.job_retries_action : job->function->options.job_retries_action; + if (job_retries != 0 && job_retries <= job->retries) { + if (job_retries_action.empty() == false) + { + 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 +417,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,51 +440,173 @@ } /* 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; + gearman_server_job_wakeup_workers(job); + } - do + /* Queue the job to be run. */ + if (job->job_queued == false) + { + if (job->function->job_list[job->priority] == NULL) { - if (worker->con->is_sleeping && ! (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; - noop_sent++; - } - } - - worker= worker->function_next; + job->function->job_list[job->priority]= job; } - while (worker != job->function->worker_list && - (Server->worker_wakeup == 0 || - noop_sent < Server->worker_wakeup)); - - job->function->worker_list= worker; + 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; } - - /* Queue the job to be run. */ - if (job->function->job_list[job->priority] == NULL) + else if (job->when == 0) { - job->function->job_list[job->priority]= job; + 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-12-19 17:57:13.228612235 +0800 @@ -123,11 +123,22 @@ gearman_server_job_take(gearman_server_con_st *server_con); /** + * Wake up workers for a job + */ +void gearman_server_job_wakeup_workers(gearman_server_job_st *server_job); + +/** * Queue a job to be run. */ 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/plugins/queue/redis/queue.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/plugins/queue/redis/queue.cc 2014-12-23 15:51:08.224799695 +0800 @@ -93,6 +93,7 @@ std::string server; std::string service; + std::string password; private: redisContext *_redis; @@ -102,11 +103,13 @@ Queue("redis"), server("127.0.0.1"), service("6379"), + password(""), _redis(NULL) { command_line_options().add_options() ("redis-server", boost::program_options::value(&server), "Redis server") - ("redis-port", boost::program_options::value(&service), "Redis server port/service"); + ("redis-port", boost::program_options::value(&service), "Redis server port/service") + ("redis-password", boost::program_options::value(&password), "Redis server password"); } Hiredis::~Hiredis() @@ -116,10 +119,20 @@ gearmand_error_t Hiredis::initialize() { int service_port= atoi(service.c_str()); - if ((_redis= redisConnect("127.0.0.1", service_port)) == NULL) + if ((_redis= redisConnect(server.c_str(), service_port)) == NULL) { return gearmand_gerror("Could not connect to redis server", GEARMAND_QUEUE_ERROR); } + if (password.size()) + { + redisReply *reply= (redisReply*)redisCommand(_redis, "AUTH %s", password.c_str()); + if (reply == NULL) + { + return gearmand_gerror("Could not auth with redis server", GEARMAND_QUEUE_ERROR); + } + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires auth reply: %.*s", (uint32_t)reply->len, reply->str); + freeReplyObject(reply); + } gearmand_info("Initializing hiredis module"); @@ -140,7 +153,7 @@ typedef std::vector vchar_t; #define GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX "_gear_" #define GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX_SIZE sizeof(GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX) -#define GEARMAND_KEY_LITERAL "%s-%.*s-%*s" +#define GEARMAND_KEY_LITERAL "%s %.*s %.*s" static size_t build_key(vchar_t &key, const char *unique, @@ -148,7 +161,7 @@ const char *function_name, size_t function_name_size) { - key.resize(function_name_size +unique_size +GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX_SIZE +4); + key.resize(function_name_size +unique_size +GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX_SIZE +2); int key_size= snprintf(&key[0], key.size(), GEARMAND_KEY_LITERAL, GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX, (int)function_name_size, function_name, @@ -186,28 +199,23 @@ const char *function_name, size_t function_name_size, const void *data, size_t data_size, - gearman_job_priority_t, + gearman_job_priority_t priority, int64_t when) { gearmand::plugins::queue::Hiredis *queue= (gearmand::plugins::queue::Hiredis *)context; - if (when) // No support for EPOCH jobs - { - return GEARMAND_QUEUE_ERROR; - } - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires add: %.*s", (uint32_t)unique_size, (char *)unique); std::vector key; build_key(key, unique, unique_size, function_name, function_name_size); gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires key: %u", (uint32_t)key.size()); - redisReply *reply= (redisReply*)redisCommand(queue->redis(), "SET %b %b", &key[0], key.size(), data, data_size); - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "got reply"); + redisReply *reply= (redisReply*)redisCommand(queue->redis(), "SET %b p:%hu,w:%lu,d:%b", &key[0], key.size(), (uint16_t)priority, when, data, data_size); if (reply == NULL) { - return gearmand_log_gerror(GEARMAN_DEFAULT_LOG_PARAM, GEARMAND_QUEUE_ERROR, "failed to insert '%.*s' into redis", key.size(), &key[0]); + return gearmand_log_gerror(GEARMAN_DEFAULT_LOG_PARAM, GEARMAND_QUEUE_ERROR, "hires failed to insert '%.*s' into redis", key.size(), &key[0]); } + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires queue reply: %.*s", (uint32_t)reply->len, reply->str); freeReplyObject(reply); return GEARMAND_SUCCESS; @@ -252,49 +260,80 @@ gearmand_info("hiredis replay start"); - redisReply *reply= (redisReply*)redisCommand(queue->redis(), "KEYS %s", GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX); + redisReply *reply= (redisReply*)redisCommand(queue->redis(), "KEYS %s*", GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX); if (reply == NULL) { return gearmand_gerror("Failed to call KEYS during QUEUE replay", GEARMAND_QUEUE_ERROR); } + gearmand_log_info(GEARMAN_DEFAULT_LOG_PARAM, "hires keys: %u", reply->elements); + + char fmt_str[16] = ""; + int fmt_str_length= snprintf(fmt_str, sizeof(fmt_str), "%%%ds%%%ds%%%ds", + int(GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX_SIZE), + int(GEARMAN_FUNCTION_MAX_SIZE), + int(GEARMAN_MAX_UNIQUE_SIZE)); + if (fmt_str_length <= 0 or size_t(fmt_str_length) >= sizeof(fmt_str)) + { + assert(fmt_str_length != 1); + return gearmand_gerror("snprintf() failed to produce a valud fmt_str for redis key", GEARMAND_QUEUE_ERROR); + } + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires fmt_str: %s", fmt_str); for (size_t x= 0; x < reply->elements; x++) { - char prefix[GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX_SIZE]; - char function_name[GEARMAN_FUNCTION_MAX_SIZE]; - char unique[GEARMAN_MAX_UNIQUE_SIZE]; - - char fmt_str[100] = ""; - int fmt_str_length= snprintf(fmt_str, sizeof(fmt_str), "%%%ds-%%%ds-%%%ds", - int(GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX_SIZE), - int(GEARMAN_FUNCTION_MAX_SIZE), - int(GEARMAN_MAX_UNIQUE_SIZE)); - if (fmt_str_length <= 0 or size_t(fmt_str_length) >= sizeof(fmt_str)) - { - assert(fmt_str_length != 1); - return gearmand_gerror("snprintf() failed to produce a valud fmt_str for redis key", GEARMAND_QUEUE_ERROR); - } + char prefix[GEARMAND_QUEUE_GEARMAND_DEFAULT_PREFIX_SIZE] = ""; + char function_name[GEARMAN_FUNCTION_MAX_SIZE] = ""; + char unique[GEARMAN_MAX_UNIQUE_SIZE] = ""; int ret= sscanf(reply->element[x]->str, fmt_str, prefix, function_name, unique); - if (ret == 0) + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires key prefix: %s, function_name: %s, unique: %s", prefix, function_name, unique); + if (ret == 0 or strlen(function_name) == 0 or strlen(unique) == 0) { continue; } - redisReply *get_reply= (redisReply*)redisCommand(queue->redis(), "GET %s", reply->element[x]->str); + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires get: %.*s", strlen(unique), unique); + redisReply *get_reply= (redisReply*)redisCommand(queue->redis(), "GET %b", reply->element[x]->str, reply->element[x]->len); if (get_reply == NULL) { + gearmand_log_warning(GEARMAN_DEFAULT_LOG_PARAM, "hires failed to get '%.*s' from redis", reply->element[x]->len, reply->element[x]->str); continue; } + size_t data_size= get_reply->len; + char *data= (char *)malloc(data_size); + if (data == NULL) + { + return gearmand_perror(errno, "malloc failed"); + } + + uint16_t priority= (uint16_t)GEARMAN_JOB_PRIORITY_NORMAL; + uint64_t when= 0; + ret= sscanf(get_reply->str, "p:%hu,w:%lu,d:", &priority, &when); + if (ret == 2) + { + char *c= get_reply->str; + for (int i= 0; i < 3; i++) + { + c= index(c, ':') +1; + } + data_size-= c -get_reply->str; + memcpy(data, c, data_size); + } + else + { + memcpy(data, get_reply->str, data_size); + } + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "hires value priority: %hu, when: %lu, data_size: %u, data: %.*s", priority, when, data_size, data_size, data); + (void)(add_fn)(server, add_context, unique, strlen(unique), function_name, strlen(function_name), - get_reply->str, get_reply->len, - GEARMAN_JOB_PRIORITY_NORMAL, 0); + data, data_size, + (gearman_job_priority_t)priority, when); freeReplyObject(get_reply); } freeReplyObject(reply); --- 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-12-23 11:56:47.000603151 +0800 @@ -37,19 +37,153 @@ #pragma once +struct gearman_server_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 job_worker_ratio_max; // Set maximum job / worker ratio when an action will be taken. + uint32_t job_worker_ratio_max_interval; // Set interval of actions for job_worker_ratio_max. + uint32_t job_worker_ratio_min; // Set minimum job / worker ratio when an action will be taken. + uint32_t job_worker_ratio_min_interval; // Set interval of actions for job_worker_ratio_min. + uint32_t worker_count_max; // Set maximum worker count when an action will be taken. + uint32_t worker_count_max_interval; // Set interval of actions for worker_count_max. + uint32_t worker_count_min; // Set minimum 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. + std::string job_retries_action; // Set action for job retries reaching job_retries. + std::string job_retries_warn_action; // Set action for job retries reaching job_retries_warn. + std::string job_count_max_action; // Set action for job count more than job_count_max. + std::string job_worker_ratio_max_action; // Set action for job / worker ration more than job_worker_ratio_max. + std::string job_worker_ratio_min_action; // Set action for job / worker ration less than job_worker_ratio_min. + std::string worker_count_max_action; // Set action for worker count more than worker_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. + timer_t job_count_max_timer; // Set timer for job count more than job_count_max. + timer_t job_worker_ratio_max_timer; // Set timer for job / worker ration more than job_worker_ratio_max. + timer_t job_worker_ratio_min_timer; // Set timer for job / worker ration less than job_worker_ratio_min. + timer_t worker_count_max_timer; // Set timer for worker count less than worker_count_min. + timer_t worker_count_min_timer; // Set timer for worker count more than worker_count_max. + + gearman_server_options_st(): + job_retries(0), + job_retries_warn(0), + job_count_max(0), + job_count_max_interval(0), + job_worker_ratio_max(0), + job_worker_ratio_max_interval(0), + job_worker_ratio_min(0), + job_worker_ratio_min_interval(0), + worker_count_max(0), + worker_count_max_interval(0), + worker_count_min(0), + worker_count_min_interval(0), + worker_wakeup(0), + job_retries_action(""), + job_retries_warn_action(""), + job_count_max_action(""), + job_worker_ratio_max_action(""), + job_worker_ratio_min_action(""), + worker_count_max_action(""), + worker_count_min_action(""), + worker_failed_action(""), + job_count_max_timer(NULL), + job_worker_ratio_max_timer(NULL), + job_worker_ratio_min_timer(NULL), + worker_count_max_timer(NULL), + worker_count_min_timer(NULL) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= (gearman_job_priority_t)((int)priority +1)) + { + max_queue_size[priority]= 0; + } + } + + gearman_server_options_st& operator=(const gearman_server_options_st& options) + { + job_retries= options.job_retries; + job_retries_warn= options.job_retries_warn; + job_count_max= options.job_count_max; + job_count_max_interval= options.job_count_max_interval; + job_worker_ratio_max= options.job_worker_ratio_max; + job_worker_ratio_max_interval= options.job_worker_ratio_max_interval; + job_worker_ratio_min= options.job_worker_ratio_min; + job_worker_ratio_min_interval= options.job_worker_ratio_min_interval; + worker_count_max= options.worker_count_max; + worker_count_max_interval= options.worker_count_max_interval; + worker_count_min= options.worker_count_min; + worker_count_min_interval= options.worker_count_min_interval; + worker_wakeup= options.worker_wakeup; + job_count_max_action= options.job_count_max_action; + job_retries_action= options.job_retries_action; + job_retries_warn_action= options.job_retries_warn_action; + job_worker_ratio_max_action= options.job_worker_ratio_max_action; + job_worker_ratio_min_action= options.job_worker_ratio_min_action; + worker_count_max_action= options.worker_count_max_action; + worker_count_min_action= options.worker_count_min_action; + worker_failed_action= options.worker_failed_action; + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= (gearman_job_priority_t)((int)priority +1)) + { + max_queue_size[priority]= options.max_queue_size[priority]; + } + return *this; + } + + ~gearman_server_options_st() + { + if (job_count_max_timer != NULL) + { + timer_delete(job_count_max_timer); + job_count_max_timer = NULL; + } + if (job_worker_ratio_max_timer != NULL) + { + timer_delete(job_worker_ratio_max_timer); + job_worker_ratio_max_timer = NULL; + } + if (job_worker_ratio_min_timer != NULL) + { + timer_delete(job_worker_ratio_min_timer); + job_worker_ratio_min_timer = NULL; + } + if (worker_count_max_timer != NULL) + { + timer_delete(worker_count_max_timer); + worker_count_max_timer = NULL; + } + if (worker_count_min_timer != NULL) + { + timer_delete(worker_count_min_timer); + worker_count_min_timer = NULL; + } + } +}; + 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 gearman_server_options_st options; }; +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-09-06 21:22:54.401947818 +0800 @@ -43,6 +43,7 @@ { uint8_t retries; gearman_job_priority_t priority; + bool skip_job; bool ignore_job; bool job_queued; uint32_t job_handle_key; @@ -60,6 +61,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 +70,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-10-03 20:33:26.676388982 +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,8 @@ 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 gearman_server_options_st options; gearman_server_st() { --- libgearman-server/text.cc 2014-02-12 08:05:28.000000000 +0800 +++ libgearman-server/text.cc 2014-12-19 19:21:29.118922613 +0800 @@ -46,220 +46,2255 @@ #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_JOB_SKIPPED "ERR JOB_SKIPPED\r\n" +#define TEXT_ERROR_JOB_NOT_SKIPPED "ERR JOB_NOT_SKIPPED\r\n" +#define TEXT_ERROR_FUNCTION_HAS_WORKER "ERR FUNCTION_HAS_WORKER\r\n" -gearmand_error_t server_run_text(gearman_server_con_st *server_con, - gearmand_packet_st *packet) +static void status_server_function(gearman_vector_st &data, gearman_server_function_st *server_function) { - gearman_vector_st data(GEARMAND_TEXT_RESPONSE_SIZE); + 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"); +} - if (packet->argc) +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) { - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "text command %.*s %d arguments", - packet->arg_size[0], packet->arg[0], - int(packet->argc)); + 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); + } +} -#if 0 - const struct gearman_command_info_st *command= NULL; -#endif - if (packet->argc == 0) +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_printf(TEXT_ERROR_UNKNOWN_COMMAND, 4, "NULL"); + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_SUCCESS); } -#if 0 - else if ((command= gearman_command_lookup((char *)(packet->arg[0]), packet->arg_size[0]))) + else if (ret == GEARMAND_JOB_CANCELED) { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_JOB_CANCELED); } -#endif - else if (strcasecmp("workers", (char *)(packet->arg[0])) == 0) + 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%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, + server_job->skip_job, 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%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, + server_job->skip_job, 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); +} + +static void skip_server_job_unique(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_skip(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_SKIPPED) + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_JOB_SKIPPED); + } + else + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void skip_server_job_handle(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_skip(server_job); + if (ret == GEARMAND_SUCCESS) + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_SUCCESS); + } + else if (ret == GEARMAND_JOB_SKIPPED) + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_JOB_SKIPPED); + } + else + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void turnback_server_job_unique(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_turnback(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_SKIPPED) + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_JOB_NOT_SKIPPED); + } + else + { + data.vec_append_printf("%.*s\t%s", server_job->unique_length, server_job->unique, TEXT_ERROR_INTERNAL_ERROR); + } +} + +static void turnback_server_job_handle(gearman_vector_st &data, gearman_server_job_st *server_job) +{ + gearmand_error_t ret= _gearman_server_job_turnback(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_SKIPPED) + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_JOB_NOT_SKIPPED); + } + else + { + data.vec_append_printf("%s\t%s", server_job->job_handle, TEXT_ERROR_INTERNAL_ERROR); + } +} + +struct Options_use_st { + bool job_retries; + bool job_retries_warn; + bool job_count_max; + bool job_count_max_interval; + bool job_worker_ratio_max; + bool job_worker_ratio_max_interval; + bool job_worker_ratio_min; + bool job_worker_ratio_min_interval; + bool worker_count_max; + bool worker_count_max_interval; + bool worker_count_min; + bool worker_count_min_interval; + bool worker_wakeup; + bool max_queue_size[GEARMAN_JOB_PRIORITY_MAX]; + bool job_retries_action; + bool job_retries_warn_action; + bool job_count_max_action; + bool job_worker_ratio_max_action; + bool job_worker_ratio_min_action; + bool worker_count_max_action; + bool worker_count_min_action; + bool worker_failed_action; + + Options_use_st(): + job_retries(false), + job_retries_warn(false), + job_count_max(false), + job_count_max_interval(false), + job_worker_ratio_max(false), + job_worker_ratio_max_interval(false), + job_worker_ratio_min(false), + job_worker_ratio_min_interval(false), + worker_count_max(false), + worker_count_max_interval(false), + worker_count_min(false), + worker_count_min_interval(false), + worker_wakeup(false), + job_retries_action(false), + job_retries_warn_action(false), + job_count_max_action(false), + job_worker_ratio_max_action(false), + job_worker_ratio_min_action(false), + worker_count_max_action(false), + worker_count_min_action(false), + worker_failed_action(false) + { + for (gearman_job_priority_t priority= GEARMAN_JOB_PRIORITY_HIGH; priority < GEARMAN_JOB_PRIORITY_MAX; priority= (gearman_job_priority_t)((int)priority +1)) + { + max_queue_size[priority]= false; + } + } +}; + +static void parse_options(const char *argv, struct gearman_server_options_st &options, struct Options_use_st &options_use) +{ + 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.job_retries= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_retries= true; + } + else if (klength == 16 and strncasecmp("job_retries_warn", args, klength) == 0) + { + options.job_retries_warn= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_retries_warn= true; + } + else if (klength == 13 and strncasecmp("job_count_max", args, klength) == 0) + { + options.job_count_max= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_count_max= true; + } + else if (klength == 22 and strncasecmp("job_count_max_interval", args, klength) == 0) + { + options.job_count_max_interval= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_count_max_interval= true; + } + else if (klength == 20 and strncasecmp("job_worker_ratio_max", args, klength) == 0) + { + options.job_worker_ratio_max= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_worker_ratio_max= true; + } + else if (klength == 29 and strncasecmp("job_worker_ratio_max_interval", args, klength) == 0) + { + options.job_worker_ratio_max_interval= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_worker_ratio_max_interval= true; + } + else if (klength == 20 and strncasecmp("job_worker_ratio_min", args, klength) == 0) + { + options.job_worker_ratio_min= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_worker_ratio_min= true; + } + else if (klength == 29 and strncasecmp("job_worker_ratio_min_interval", args, klength) == 0) + { + options.job_worker_ratio_min_interval= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.job_worker_ratio_min_interval= true; + } + else if (klength == 16 and strncasecmp("worker_count_max", args, klength) == 0) + { + options.worker_count_max= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.worker_count_max= true; + } + else if (klength == 25 and strncasecmp("worker_count_max_interval", args, klength) == 0) + { + options.worker_count_max_interval= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.worker_count_max_interval= true; + } + else if (klength == 16 and strncasecmp("worker_count_min", args, klength) == 0) + { + options.worker_count_min= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.worker_count_min= true; + } + else if (klength == 25 and strncasecmp("worker_count_min_interval", args, klength) == 0) + { + options.worker_count_min_interval= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.worker_count_min_interval= true; + } + else if (klength == 13 and strncasecmp("worker_wakeup", args, klength) == 0) + { + options.worker_wakeup= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.worker_wakeup= true; + } + 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.max_queue_size[priority]= (vlength == 0) ? 0 : (uint32_t)strtoul(args +klength +1, NULL, 10); + options_use.max_queue_size[priority]= true; + } + } + else if (klength == 18 and strncasecmp("job_retries_action", args, klength) == 0) + { + if (vlength > 0) + { + options.job_retries_action.assign(args +klength +1, vlength); + options_use.job_retries_action= true; + } + else if (options.job_retries_warn_action.empty() == false) + { + options.job_retries_action= ""; + options_use.job_retries_action= true; + } + } + else if (klength == 23 and strncasecmp("job_retries_warn_action", args, klength) == 0) + { + if (vlength > 0) + { + options.job_retries_warn_action.assign(args +klength +1, vlength); + options_use.job_retries_warn_action= true; + } + else if (options.job_retries_warn_action.empty() == false) + { + options.job_retries_warn_action= ""; + options_use.job_retries_warn_action= true; + } + } + else if (klength == 20 and strncasecmp("job_count_max_action", args, klength) == 0) + { + if (vlength > 0) + { + options.job_count_max_action.assign(args +klength +1, vlength); + options_use.job_count_max_action= true; + } + else if (options.job_count_max_action.empty() == false) + { + options.job_count_max_action= ""; + options_use.job_count_max_action= true; + } + } + else if (klength == 27 and strncasecmp("job_worker_ratio_max_action", args, klength) == 0) + { + if (vlength > 0) + { + options.job_worker_ratio_max_action.assign(args +klength +1, vlength); + options_use.job_worker_ratio_max_action= true; + } + else if (options.job_worker_ratio_max_action.empty() == false) + { + options.job_worker_ratio_max_action= ""; + options_use.job_worker_ratio_max_action= true; + } + } + else if (klength == 27 and strncasecmp("job_worker_ratio_min_action", args, klength) == 0) + { + if (vlength > 0) + { + options.job_worker_ratio_min_action.assign(args +klength +1, vlength); + options_use.job_worker_ratio_min_action= true; + } + else if (options.job_worker_ratio_min_action.empty() == false) + { + options.job_worker_ratio_min_action= ""; + options_use.job_worker_ratio_min_action= true; + } + } + else if (klength == 23 and strncasecmp("worker_count_max_action", args, klength) == 0) + { + if (vlength > 0) + { + options.worker_count_max_action.assign(args +klength +1, vlength); + options_use.worker_count_max_action= true; + } + else if (options.worker_count_max_action.empty() == false) + { + options.worker_count_max_action= ""; + options_use.worker_count_max_action= true; + } + } + else if (klength == 23 and strncasecmp("worker_count_min_action", args, klength) == 0) + { + if (vlength > 0) + { + options.worker_count_min_action.assign(args +klength +1, vlength); + options_use.worker_count_min_action= true; + } + else if (options.worker_count_min_action.empty() == false) + { + options.worker_count_min_action= ""; + options_use.worker_count_min_action= true; + } + } + else if (klength == 20 and strncasecmp("worker_failed_action", args, klength) == 0) + { + if (vlength > 0) + { + options.worker_failed_action.assign(args +klength +1, vlength); + options_use.worker_failed_action= true; + } + else if (options.worker_failed_action.empty() == false) + { + options.worker_failed_action= ""; + options_use.worker_failed_action= true; + } + } + } + } + args+= (length +1); + size-= (length +1); + } +} + +static void apply_options(gearman_server_function_st *server_function, struct gearman_server_options_st &new_options, struct Options_use_st &options_use) +{ + struct gearman_server_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.job_worker_ratio_max == true) + { + options.job_worker_ratio_max = new_options.job_worker_ratio_max; + } + if (options_use.job_worker_ratio_max_interval == true) + { + options.job_worker_ratio_max_interval = new_options.job_worker_ratio_max_interval; + } + if (options_use.job_worker_ratio_min == true) + { + options.job_worker_ratio_min = new_options.job_worker_ratio_min; + } + if (options_use.job_worker_ratio_min_interval == true) + { + options.job_worker_ratio_min_interval = new_options.job_worker_ratio_min_interval; + } + if (options_use.worker_count_max == true) + { + options.worker_count_max= new_options.worker_count_max; + } + if (options_use.worker_count_max_interval == true) + { + options.worker_count_max_interval= new_options.worker_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 (options_use.job_retries_action == true) + { + options.job_retries_action= new_options.job_retries_action; + } + if (options_use.job_retries_warn_action == true) + { + options.job_retries_warn_action= new_options.job_retries_warn_action; + } + if (options_use.job_count_max_action == true) + { + options.job_count_max_action= new_options.job_count_max_action; + } + if (options_use.job_worker_ratio_max_action == true) + { + options.job_worker_ratio_max_action= new_options.job_worker_ratio_max_action; + } + if (options_use.job_worker_ratio_min_action == true) + { + options.job_worker_ratio_min_action= new_options.job_worker_ratio_min_action; + } + if (options_use.worker_count_max_action == true) + { + options.worker_count_max_action= new_options.worker_count_max_action; + } + if (options_use.worker_count_min_action == true) + { + options.worker_count_min_action= new_options.worker_count_min_action; + } + if (options_use.worker_failed_action == true) + { + options.worker_failed_action= new_options.worker_failed_action; + } + + if (options_use.job_count_max == true or options_use.job_count_max_interval == true or options_use.job_count_max_action == true) + { + gearman_server_timer_job_count_max(Server, server_function); + } + if (options_use.job_worker_ratio_max == true or options_use.job_worker_ratio_max_interval == true or options_use.job_worker_ratio_max_action == true) + { + gearman_server_timer_job_worker_ratio_max(Server, server_function); + } + if (options_use.job_worker_ratio_min == true or options_use.job_worker_ratio_min_interval == true or options_use.job_worker_ratio_min_action == true) + { + gearman_server_timer_job_worker_ratio_min(Server, server_function); + } + if (options_use.worker_count_max == true or options_use.worker_count_max_interval == true or options_use.worker_count_max_action == true) + { + gearman_server_timer_worker_count_max(Server, server_function); + } + if (options_use.worker_count_min == true or options_use.worker_count_min_interval == true or options_use.worker_count_min_action == 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 gearman_server_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\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.job_worker_ratio_max, options.job_worker_ratio_max_interval, + options.job_worker_ratio_min, options.job_worker_ratio_min_interval, + options.worker_count_max, options.worker_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("\t%.*s\t%.*s\t%.*s\t%.*s\t%.*s\t%.*s\t%.*s\t%.*s", + options.job_retries_action.size(), options.job_retries_action.c_str(), + options.job_retries_warn_action.size(), options.job_retries_warn_action.c_str(), + options.job_count_max_action.size(), options.job_count_max_action.c_str(), + options.job_worker_ratio_max_action.size(), options.job_worker_ratio_max_action.c_str(), + options.job_worker_ratio_min_action.size(), options.job_worker_ratio_min_action.c_str(), + options.worker_count_max_action.size(), options.worker_count_max_action.c_str(), + options.worker_count_min_action.size(), options.worker_count_min_action.c_str(), + options.worker_failed_action.size(), options.worker_failed_action.c_str()); + 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) +{ + gearman_vector_st data(GEARMAND_TEXT_RESPONSE_SIZE); + + if (packet->argc) + { + gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "text command %.*s %d arguments", + packet->arg_size[0], packet->arg[0], + int(packet->argc)); + } + +#if 0 + const struct gearman_command_info_st *command= NULL; +#endif + if (packet->argc == 0) + { + data.vec_printf(TEXT_ERROR_UNKNOWN_COMMAND, 4, "NULL"); + } +#if 0 + else if ((command= gearman_command_lookup((char *)(packet->arg[0]), packet->arg_size[0]))) + { + } +#endif + else if (strcasecmp("workers", (char *)(packet->arg[0])) == 0) + { + for (gearman_server_thread_st *thread= Server->thread_list; + thread != NULL; + thread= thread->next) + { + int error; + if ((error= pthread_mutex_lock(&thread->lock)) == 0) + { + for (gearman_server_con_st *con= thread->con_list; con != NULL; con= con->next) + { + if (con->_host == NULL) + { + continue; + } + + data.vec_append_printf("%d %s %s :", con->con.fd(), con->_host, con->id); + + for (gearman_server_worker_st *worker= con->worker_list; worker != NULL; worker= worker->con_next) + { + data.vec_append_printf(" %.*s", + (int)(worker->function->function_name_size), + worker->function->function_name); + } + + data.vec_append_printf("\n"); + } + + if ((error= (pthread_mutex_unlock(&(thread->lock)))) != 0) + { + gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock"); + } + } + else + { + gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock"); + } + } + + data.vec_append_printf(TEXT_END); + } + else if (strcasecmp("status", packet->arg[0]) == 0) + { + 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 (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) + { + status_server_function(data, server_function); + } + } + } + data.vec_append_printf(TEXT_END); + } + else if (strcasecmp("cancel", 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_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) + { + 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); + } + } + else if (packet->argc >= 3 and strcasecmp("job", packet->arg[1]) == 0) + { + gearmand_error_t ret= gearman_server_job_cancel(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_CANCELED) + { + data.vec_printf(TEXT_ERROR_JOB_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) + { + 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); + } + } + 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 == 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 + { + 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 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) + { + cancel_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 == 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(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("skip", packet->arg[0]) == 0) { - for (gearman_server_thread_st *thread= Server->thread_list; - thread != NULL; - thread= thread->next) + if (packet->argc >= 4 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("job", packet->arg[2]) == 0) { - int error; - if ((error= pthread_mutex_lock(&thread->lock)) == 0) + gearmand_error_t ret= gearman_server_job_skip_by_unique(Gearmand()->server, packet->arg[3], strlen(packet->arg[3])); + if (ret == GEARMAND_SUCCESS) { - for (gearman_server_con_st *con= thread->con_list; con != NULL; con= con->next) + data.vec_printf(TEXT_SUCCESS); + } + else if (ret == GEARMAND_NO_JOBS) + { + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_SKIPPED) + { + data.vec_printf(TEXT_ERROR_JOB_SKIPPED); + } + 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_skip(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_SKIPPED) + { + data.vec_printf(TEXT_ERROR_JOB_SKIPPED); + } + 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) { - if (con->_host == NULL) + char *comma= (char *)memchr(args, ',', size); + int64_t length= (comma == NULL) ? size : (comma -args); + if (length > 0) { - continue; + gearman_server_job_st *server_job= gearman_server_job_get_by_unique(Server, args, length, NULL); + if (server_job != NULL) + { + skip_server_job_unique(data, server_job); + } + else + { + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_JOB); + } } - - data.vec_append_printf("%d %s %s :", con->con.fd(), con->_host, con->id); - - for (gearman_server_worker_st *worker= con->worker_list; worker != NULL; worker= worker->con_next) + 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) { - data.vec_append_printf(" %.*s", - (int)(worker->function->function_name_size), - worker->function->function_name); + 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->skip_job == false) + { + skip_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->skip_job == false) + { + skip_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->skip_job == false) + { + skip_server_job_unique(data, server_job); + } + } + } + } } - - data.vec_append_printf("\n"); + args+= (length +1); + size-= (length +1); } - - if ((error= (pthread_mutex_unlock(&(thread->lock)))) != 0) + } + else + { + for (size_t x= 0; x < Server->hashtable_buckets; x++) { - gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_unlock"); + for (gearman_server_job_st* server_job= Server->unique_hash[x]; server_job != NULL; server_job= server_job->unique_next) + { + if (server_job->skip_job == false) + { + skip_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) + { + skip_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->skip_job == false) + { + skip_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->skip_job == false) + { + skip_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->skip_job == false) + { + skip_server_job_handle(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); } } else { - gearmand_log_fatal_perror(GEARMAN_DEFAULT_LOG_PARAM, error, "pthread_mutex_lock"); + 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->skip_job == false) + { + skip_server_job_handle(data, server_job); + } + } + } } + data.vec_append_printf(TEXT_END); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_CANCEL_ARGUMENTS); } - - data.vec_append_printf(".\n"); } - else if (strcasecmp("status", (char *)(packet->arg[0])) == 0) + else if (strcasecmp("turnback", packet->arg[0]) == 0) { - for (uint32_t function_key= 0; - function_key < GEARMAND_DEFAULT_HASH_SIZE; - function_key++) + if (packet->argc >= 4 and strcasecmp("unique", packet->arg[1]) == 0 and strcasecmp("job", packet->arg[2]) == 0) { - for (gearman_server_function_st *function= Server->function_hash[function_key]; - function != NULL; - function= function->next) + gearmand_error_t ret= gearman_server_job_turnback_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_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); + data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_NOT_SKIPPED) + { + data.vec_printf(TEXT_ERROR_JOB_NOT_SKIPPED); + } + else + { + data.vec_printf(TEXT_ERROR_INTERNAL_ERROR); } } - - data.vec_append_printf(".\n"); - } - else if (packet->argc >= 3 - and strcasecmp("cancel", (char *)(packet->arg[0])) == 0) - { - if (packet->argc == 3 - and strcasecmp("job", (char *)(packet->arg[1])) == 0) + else if (packet->argc >= 3 and strcasecmp("job", packet->arg[1]) == 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_turnback(Gearmand()->server, packet->arg[2], strlen(packet->arg[2])); 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_UNKNOWN_JOB); + } + else if (ret == GEARMAND_JOB_NOT_SKIPPED) + { + data.vec_printf(TEXT_ERROR_JOB_NOT_SKIPPED); + } + 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) + { + turnback_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->skip_job == true) + { + turnback_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->skip_job == true) + { + turnback_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->skip_job == true) + { + turnback_server_job_unique(data, server_job); + } + } + } + } + } + args+= (length +1); + size-= (length +1); + } + } else { - data.vec_printf(TEXT_ERROR_UNKNOWN_JOB); + 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->skip_job == true) + { + turnback_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) + { + turnback_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->skip_job == true) + { + turnback_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->skip_job == true) + { + turnback_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->skip_job == true) + { + turnback_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->skip_job == true) + { + turnback_server_job_handle(data, server_job); + } + } + } } + data.vec_append_printf(TEXT_END); + } + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_RESTORE_ARGUMENTS); } } - else if (packet->argc >= 2 and strcasecmp("show", (char *)(packet->arg[0])) == 0) + else if (strcasecmp("config", packet->arg[0]) == 0) { - if (packet->argc == 3 - and strcasecmp("unique", (char *)(packet->arg[1])) == 0 - and strcasecmp("jobs", (char *)(packet->arg[2])) == 0) + struct Options_use_st options_use; + struct gearman_server_options_st options; + if (packet->argc >= 3 and strcasecmp("function", packet->arg[1]) == 0) { - for (size_t x= 0; x < Server->hashtable_buckets; x++) + gearman_server_function_st *server_function= gearman_server_function_get(Server, packet->arg[2], strlen(packet->arg[2]), false); + if (server_function != NULL) { - for (gearman_server_job_st* server_job= Server->unique_hash[x]; - server_job != NULL; - server_job= server_job->unique_next) + 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 { - data.vec_append_printf("%.*s\n", int(server_job->unique_length), server_job->unique); + print_options(data, server_function); } } - - data.vec_append_printf(".\n"); + else + { + data.vec_printf(TEXT_ERROR_UNKNOWN_FUNCTION); + } } - else if (packet->argc == 2 - and strcasecmp("jobs", (char *)(packet->arg[1])) == 0) + else if (packet->argc >= 2 and strcasecmp("functions", packet->arg[1]) == 0) { - for (size_t x= 0; x < Server->hashtable_buckets; ++x) + 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 (gearman_server_job_st *server_job= Server->job_hash[x]; - server_job != NULL; - server_job= server_job->next) + for (size_t x= 0; x < GEARMAND_DEFAULT_HASH_SIZE; x++) { - 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)); + 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(".\n"); + 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_SHOW_ARGUMENTS); + data.vec_printf(TEXT_ERROR_UNKNOWN_CONFIG_ARGUMENTS); } } - else if (strcasecmp("create", (char *)(packet->arg[0])) == 0) + else if (strcasecmp("create", packet->arg[0]) == 0) { - if (packet->argc == 3 and strcasecmp("function", (char *)(packet->arg[1])) == 0) + if (packet->argc >= 3 and strcasecmp("function", 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) + 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, - (int)packet->arg_size[2], (char *)(packet->arg[2])); + 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 { - // create - data.vec_printf(TEXT_ERROR_ARGS, (int)packet->arg_size[0], (char *)(packet->arg[0])); + data.vec_printf(TEXT_ERROR_UNKNOWN_CREATE_ARGUMENTS); } } - else if (strcasecmp("drop", (char *)(packet->arg[0])) == 0) + else if (strcasecmp("drop", packet->arg[0]) == 0) { - if (packet->argc == 3 and strcasecmp("function", (char *)(packet->arg[1])) == 0) + if (packet->argc >= 3 and strcasecmp("function", packet->arg[1]) == 0) { - bool success= false; - for (uint32_t function_key= 0; function_key < GEARMAND_DEFAULT_HASH_SIZE; - function_key++) + gearman_server_function_st *server_function= gearman_server_function_get(Server, packet->arg[2], strlen(packet->arg[2]), false); + if (server_function != NULL) { - for (gearman_server_function_st *function= Server->function_hash[function_key]; - function != NULL; - function= 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_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) { - 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_function_st *server_function= gearman_server_function_get(Server, args, length, false); + if (server_function != NULL) { - gearman_server_function_free(Server, function); - data.vec_append_printf(TEXT_SUCCESS); + 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("ERR there are still connected workers or executing clients\r\n"); + data.vec_append_printf("%.*s\t%s", length, args, TEXT_ERROR_UNKNOWN_FUNCTION); } - break; } + args+= (length +1); + size-= (length +1); } } - - if (success == false) + else { - data.vec_printf("ERR function not found\r\n"); - gearmand_log_debug(GEARMAN_DEFAULT_LOG_PARAM, "%s", data.value()); + 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 +2351,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;