Request processing flowchart
Civetweb, for example
1. Rgw_main. cc is the entrance to the entire RadosGW service. In main(), different front-end types are selected according to the RGW Frontend tends parameters set in ceph. This section generates different handlers for s3, SWIFT, and admin interfaces based on rgw_ENABle_apis Settings in ceph. The codes are as follows
#src/rgw/rgw_main.cc get_str_list(g_conf->rgw_enable_apis, apis); <string, bool> apis_map; for (list<string>::iterator li = apis.begin(); li ! = apis.end(); ++li) { apis_map[*li] = true; }... if (apis_map.count("s3") > 0 || s3website_enabled) { if (! swift_at_root) { rest.register_default_mgr(set_logging(new RGWRESTMgr_S3(s3website_enabled))); # set S3 handler to RGWRESTMgr_S3... if (apis_map.count("swift") > 0) { do_swift = true; swift_init(g_ceph_context); RGWRESTMgr_SWIFT* const swift_resource = new RGWRESTMgr_SWIFT; Set the default HANDLER to RGWRESTMgr_SWIFT...Copy the code
2. In the rgw_civetweb_fronte. cc file, set startup parameters based on the civetWeb startup process described before, and use mg_start() to start the civetWeb. (Note that callback is set to civetweb_callback)
#src/rgw/rgw_civetweb_frontend.cc int RGWMongooseFrontend::run() { char thread_pool_buf[32]; snprintf(thread_pool_buf, sizeof(thread_pool_buf), "%d", (int)g_conf->rgw_thread_pool_size); string port_str; map<string, string> conf_map = conf->get_config_map(); conf->get_val("port", "80", &port_str); conf_map.erase("port"); std::replace(port_str.begin(), port_str.end(), '+', ','); conf_map["listening_ports"] = port_str; Set_conf_default (conf_map, "enabLE_KEEP_alive ", "yes"); Keep_alive set_conf_default(conf_map, "num_threads", thread_pool_buf); Threads default set_conf_default(conf_map, "decode_URL ", "no"); . struct mg_callbacks cb; memset((void *)&cb, 0, sizeof(cb)); cb.begin_request = civetweb_callback; Cb.log_message = rgw_civetweb_log_callback; cb.log_access = rgw_civetweb_log_access_callback; ctx = mg_start(&cb, &env, (const char **)&options); If (! ctx) { return -EIO; } return 0; } /* RGWMongooseFrontend::run */Copy the code
3. After setting up the previous step, each civetweb_callback request needs to be processed by process_request(). Note that each request is bound to a set of RGWRados(which reads and writes the underlying Librados)/RGWREST (which processes Request and Response)/ OpsLogSocket (which logs messages)
#src/rgw/rgw_civetweb_frontend.cc static int civetweb_callback(struct mg_connection* conn) { struct mg_request_info* req_info = mg_get_request_info(conn); RGWMongooseEnv* pe = static_cast<RGWMongooseEnv *>(req_info->user_data); { // hold a read lock over access to pe->store for reconfiguration RWLock::RLocker lock(pe->mutex); RGWRados* store = pe->store; RGWREST* rest = pe->rest; OpsLogSocket* olog = pe->olog; RGWRequest req(store->get_new_req_id()); RGWMongoose client_io(conn); int ret = process_request(pe->store, rest, &req, &client_io, olog); Each request is tagged with RGWRados, RGWREST, OpsLogSocket...Copy the code
Rgw_process. cc process_request(); rest->get_handler (); Handler ->get_op(store); Then handler’s corresponding pre_exec(), execute() and complete() are triggered to complete the processing of the entire request, and the code is as follows:
#src/rgw/rgw_process.cc int process_request(RGWRados* store, RGWREST* rest, RGWRequest* req,GWStreamIO* client_io, OpsLogSocket* olog) {int ret = 0; client_io->init(g_ceph_context); . RGWHandler_REST *handler = rest->get_handler(store, s, client_io, &mgr,&init_error); If (init_error! = 0) { abort_early(s, NULL, init_error, NULL); goto done; } dout(10) << "handler=" << typeid(*handler).name() << dendl; should_log = mgr->get_logging(); req->log_format(s, "getting op %d", s->op); op = handler->get_op(store); Request_method specifies the type of handler used to process the request. req->log(s, "pre-executing"); op->pre_exec(); Req ->log(s, "executing"); op->execute(); Realizations of specific requests req->log(S, "completing"); op->complete(); Complete request processingCopy the code
#src/rgw/rgw_process.cc
RGWHandler_REST* RGWRESTMgr_S3::get_handler(struct req_state *s)
{
bool is_s3website = enable_s3website && (s->prot_flags & RGW_REST_WEBSITE);
int ret =
RGWHandler_REST_S3::init_from_header(s,
is_s3website ? RGW_FORMAT_HTML :
RGW_FORMAT_XML, true);
if (ret < 0)
return NULL;
RGWHandler_REST* handler;
// TODO: Make this more readable
if (is_s3website) {
if (s->init_state.url_bucket.empty()) {
handler = new RGWHandler_REST_Service_S3Website;
} else if (s->object.empty()) {
handler = new RGWHandler_REST_Bucket_S3Website;
} else {
handler = newRGWHandler_REST_Obj_S3Website; }}else {
if (s->init_state.url_bucket.empty()) {
handler = newRGWHandler_REST_Service_S3; RGWHandler_REST_Service_S3}else if (s->object.empty()) {
handler = newRGWHandler_REST_Bucket_S3; RGWHandler_REST_Bucket_S3}else {
handler = newRGWHandler_REST_Obj_S3; # bucket andObjectRGWHandler_REST_Obj_S3}} ldout(s-> CCT,20) << __func__ << " handler=" << typeid(*handler).name()
<< dendl;
return handler;
}
Copy the code
#src/rgw/rgw_rest.cc RGWOp* RGWHandler_REST::get_op(RGWRados* store) { RGWOp *op; Req_state {rest->op case OP_GET: op = OP_GET (); break; case OP_PUT: op = op_put(); break; case OP_DELETE: op = op_delete(); break; case OP_HEAD: op = op_head(); break; case OP_POST: op = op_post(); break; case OP_COPY: op = op_copy(); break; case OP_OPTIONS: op = op_options(); break; default: return NULL; } if (op) { op->init(store, s, this); } return op; } /* get_op */Copy the code
Struct req_state {CephContext * CCT; RGWClientIO *cio; RGWRequest *req;/// XXX: re-remove??http_op op; RGWOpType op_type; . enum http_op { OP_GET, OP_PUT, OP_DELETE, OP_HEAD, OP_POST, OP_COPY, OP_OPTIONS, OP_UNKNOWN, };Copy the code
URL – > handler process
Understand the whole PROCESS of URL conversion handler, can feel the request information to quickly locate the specific OP operation, convenient debugging, the whole process is summarized in the following figure.