| 1 | /* |
|---|
| 2 | * (C) 2003 Clemson University and The University of Chicago |
|---|
| 3 | * |
|---|
| 4 | * See COPYING in top-level directory. |
|---|
| 5 | */ |
|---|
| 6 | |
|---|
| 7 | /* pvfs2_msgpairarray_sm |
|---|
| 8 | * |
|---|
| 9 | * The purpose of this state machine is to prepare, send, and |
|---|
| 10 | * receive a collection of request/response pairs (msgpairs). |
|---|
| 11 | */ |
|---|
| 12 | |
|---|
| 13 | #include <string.h> |
|---|
| 14 | #include <assert.h> |
|---|
| 15 | |
|---|
| 16 | #include "msgpairarray.h" |
|---|
| 17 | #include "pvfs2-debug.h" |
|---|
| 18 | #include "pint-cached-config.h" |
|---|
| 19 | #include "job.h" |
|---|
| 20 | #include "gossip.h" |
|---|
| 21 | #include "PINT-reqproto-encode.h" |
|---|
| 22 | #include "pvfs2-util.h" |
|---|
| 23 | #include "pint-util.h" |
|---|
| 24 | #include "server-config-mgr.h" |
|---|
| 25 | #include "pvfs2-internal.h" |
|---|
| 26 | #include "state-machine.h" |
|---|
| 27 | |
|---|
| 28 | #define gossip_err_unless_quiet(format, f...) \ |
|---|
| 29 | do {\ |
|---|
| 30 | if(mop->params.quiet_flag)\ |
|---|
| 31 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, format, ##f); \ |
|---|
| 32 | else \ |
|---|
| 33 | gossip_err(format, ##f); \ |
|---|
| 34 | } while(0) |
|---|
| 35 | |
|---|
| 36 | enum |
|---|
| 37 | { |
|---|
| 38 | MSGPAIRS_COMPLETE = 190, |
|---|
| 39 | MSGPAIRS_RETRY = 191, |
|---|
| 40 | MSGPAIRS_RETRY_NODELAY = 192 |
|---|
| 41 | }; |
|---|
| 42 | |
|---|
| 43 | %% |
|---|
| 44 | |
|---|
| 45 | nested machine pvfs2_msgpairarray_sm |
|---|
| 46 | { |
|---|
| 47 | state init |
|---|
| 48 | { |
|---|
| 49 | run msgpairarray_init; |
|---|
| 50 | default => post; |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | state post |
|---|
| 54 | { |
|---|
| 55 | run msgpairarray_post; |
|---|
| 56 | MSGPAIRS_COMPLETE => completion_fn; |
|---|
| 57 | default => complete; |
|---|
| 58 | } |
|---|
| 59 | |
|---|
| 60 | state post_retry |
|---|
| 61 | { |
|---|
| 62 | run msgpairarray_post_retry; |
|---|
| 63 | default => post; |
|---|
| 64 | } |
|---|
| 65 | |
|---|
| 66 | state complete |
|---|
| 67 | { |
|---|
| 68 | run msgpairarray_complete; |
|---|
| 69 | MSGPAIRS_COMPLETE => completion_fn; |
|---|
| 70 | default => complete; |
|---|
| 71 | } |
|---|
| 72 | |
|---|
| 73 | state completion_fn |
|---|
| 74 | { |
|---|
| 75 | run msgpairarray_completion_fn; |
|---|
| 76 | MSGPAIRS_RETRY => post_retry; |
|---|
| 77 | MSGPAIRS_RETRY_NODELAY => post; |
|---|
| 78 | default => done; |
|---|
| 79 | } |
|---|
| 80 | |
|---|
| 81 | state done |
|---|
| 82 | { |
|---|
| 83 | run msgpairarray_done; |
|---|
| 84 | default => return; |
|---|
| 85 | } |
|---|
| 86 | } |
|---|
| 87 | |
|---|
| 88 | %% |
|---|
| 89 | |
|---|
| 90 | static PINT_sm_action msgpairarray_init( |
|---|
| 91 | struct PINT_smcb *smcb, job_status_s *js_p) |
|---|
| 92 | { |
|---|
| 93 | PINT_sm_msgarray_op *mop = PINT_sm_frame(smcb, PINT_FRAME_CURRENT); |
|---|
| 94 | int i = 0; |
|---|
| 95 | PINT_sm_msgpair_state *msg_p = NULL; |
|---|
| 96 | |
|---|
| 97 | gossip_debug(GOSSIP_MIRROR_DEBUG,"Executing msgpairarray_init...\n"); |
|---|
| 98 | gossip_debug(GOSSIP_MIRROR_DEBUG,"\tbase frame:%d\tframe count:%d\n" |
|---|
| 99 | ,smcb->base_frame,smcb->frame_count); |
|---|
| 100 | |
|---|
| 101 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, "(%p) msgpairarray state: init " |
|---|
| 102 | "(%d msgpair(s))\n", smcb, mop->count); |
|---|
| 103 | |
|---|
| 104 | assert(mop->count > 0); |
|---|
| 105 | |
|---|
| 106 | js_p->error_code = 0; |
|---|
| 107 | |
|---|
| 108 | /* set number of operations that must complete. */ |
|---|
| 109 | mop->params.comp_ct = (2 * mop->count); |
|---|
| 110 | |
|---|
| 111 | for(i = 0; i < mop->count; i++) |
|---|
| 112 | { |
|---|
| 113 | msg_p = &mop->msgarray[i]; |
|---|
| 114 | assert(msg_p); |
|---|
| 115 | |
|---|
| 116 | assert((msg_p->retry_flag == PVFS_MSGPAIR_RETRY) || |
|---|
| 117 | (msg_p->retry_flag == PVFS_MSGPAIR_NO_RETRY)); |
|---|
| 118 | |
|---|
| 119 | msg_p->encoded_resp_p = NULL; |
|---|
| 120 | msg_p->retry_count = 0; |
|---|
| 121 | msg_p->complete = 0; |
|---|
| 122 | |
|---|
| 123 | } |
|---|
| 124 | return SM_ACTION_COMPLETE; |
|---|
| 125 | } |
|---|
| 126 | |
|---|
| 127 | /* msgpairarray_post() |
|---|
| 128 | * |
|---|
| 129 | * The following elements of the PINT_sm_msgpair_state |
|---|
| 130 | * should be valid prior to this state (for each msgpair in array): |
|---|
| 131 | * - req (unencoded request) |
|---|
| 132 | * - srv_addr of each element in msg array |
|---|
| 133 | * |
|---|
| 134 | * This state performs the following operations for each msgpair, |
|---|
| 135 | * one at a time: |
|---|
| 136 | * (1) encodes request |
|---|
| 137 | * (2) calculates maximum response size |
|---|
| 138 | * (3) allocates BMI memory for response data (encoded) |
|---|
| 139 | * (4) gets a session tag for the pair of messages |
|---|
| 140 | * (5) posts the receive of the response |
|---|
| 141 | * (6) posts the send of the request |
|---|
| 142 | * (7) stores job ids for later matching |
|---|
| 143 | * |
|---|
| 144 | */ |
|---|
| 145 | static PINT_sm_action msgpairarray_post( |
|---|
| 146 | struct PINT_smcb *smcb, job_status_s *js_p) |
|---|
| 147 | { |
|---|
| 148 | PINT_sm_msgarray_op *mop = PINT_sm_frame(smcb, PINT_FRAME_CURRENT); |
|---|
| 149 | int ret = -PVFS_EINVAL, i = 0, tmp = 0; |
|---|
| 150 | struct server_configuration_s *server_config = NULL; |
|---|
| 151 | PVFS_msg_tag_t session_tag; |
|---|
| 152 | PINT_sm_msgpair_state *msg_p = NULL; |
|---|
| 153 | struct filesystem_configuration_s *cur_fs = NULL; |
|---|
| 154 | int must_loop_encodings = 0; |
|---|
| 155 | int local_enc_and_alloc = 0; |
|---|
| 156 | |
|---|
| 157 | gossip_debug( |
|---|
| 158 | GOSSIP_MSGPAIR_DEBUG, "%s: sm %p " |
|---|
| 159 | "%d total message(s) with %d incomplete\n", __func__, smcb, |
|---|
| 160 | mop->count * 2, mop->params.comp_ct); |
|---|
| 161 | |
|---|
| 162 | js_p->error_code = 0; |
|---|
| 163 | |
|---|
| 164 | assert(mop->count > 0); |
|---|
| 165 | assert(mop->params.comp_ct >= 2); |
|---|
| 166 | |
|---|
| 167 | for (i = 0; i < mop->count; i++) |
|---|
| 168 | { |
|---|
| 169 | msg_p = &mop->msgarray[i]; |
|---|
| 170 | assert(msg_p); |
|---|
| 171 | |
|---|
| 172 | /* |
|---|
| 173 | here we skip over the msgs that have already completed in |
|---|
| 174 | the case of being in the retry code path when it's ok |
|---|
| 175 | */ |
|---|
| 176 | if (msg_p->complete) |
|---|
| 177 | { |
|---|
| 178 | continue; |
|---|
| 179 | } |
|---|
| 180 | |
|---|
| 181 | msg_p->op_status = 0; |
|---|
| 182 | |
|---|
| 183 | if (msg_p->encoded_resp_p == NULL) |
|---|
| 184 | { |
|---|
| 185 | if (msg_p->fs_id != PVFS_FS_ID_NULL) |
|---|
| 186 | { |
|---|
| 187 | server_config = PINT_server_config_mgr_get_config( |
|---|
| 188 | msg_p->fs_id); |
|---|
| 189 | assert(server_config); |
|---|
| 190 | |
|---|
| 191 | cur_fs = PINT_config_find_fs_id( |
|---|
| 192 | server_config, msg_p->fs_id); |
|---|
| 193 | PINT_server_config_mgr_put_config(server_config); |
|---|
| 194 | assert(cur_fs); |
|---|
| 195 | msg_p->enc_type = cur_fs->encoding; |
|---|
| 196 | } |
|---|
| 197 | |
|---|
| 198 | if (!ENCODING_IS_VALID(msg_p->enc_type)) |
|---|
| 199 | { |
|---|
| 200 | PRINT_ENCODING_ERROR("supported", msg_p->enc_type); |
|---|
| 201 | must_loop_encodings = 1; |
|---|
| 202 | msg_p->enc_type = (ENCODING_INVALID_MIN + 1); |
|---|
| 203 | } |
|---|
| 204 | else if (!ENCODING_IS_SUPPORTED(msg_p->enc_type)) |
|---|
| 205 | { |
|---|
| 206 | PRINT_ENCODING_ERROR("supported", msg_p->enc_type); |
|---|
| 207 | must_loop_encodings = 1; |
|---|
| 208 | msg_p->enc_type = ENCODING_SUPPORTED_MIN; |
|---|
| 209 | } |
|---|
| 210 | |
|---|
| 211 | try_next_encoding: |
|---|
| 212 | assert(ENCODING_IS_VALID(msg_p->enc_type)); |
|---|
| 213 | |
|---|
| 214 | ret = PINT_encode(&msg_p->req, PINT_ENCODE_REQ, |
|---|
| 215 | &msg_p->encoded_req, msg_p->svr_addr, |
|---|
| 216 | msg_p->enc_type); |
|---|
| 217 | if (ret != 0) |
|---|
| 218 | { |
|---|
| 219 | if (must_loop_encodings) |
|---|
| 220 | { |
|---|
| 221 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, "Looping through " |
|---|
| 222 | "encodings [%d/%d]\n", msg_p->enc_type, |
|---|
| 223 | ENCODING_INVALID_MAX); |
|---|
| 224 | |
|---|
| 225 | msg_p->enc_type++; |
|---|
| 226 | if (ENCODING_IS_VALID(msg_p->enc_type)) |
|---|
| 227 | { |
|---|
| 228 | goto try_next_encoding; |
|---|
| 229 | } |
|---|
| 230 | } |
|---|
| 231 | gossip_lerr("msgpairarray_post: PINT_encode failed\n"); |
|---|
| 232 | js_p->error_code = ret; |
|---|
| 233 | return SM_ACTION_COMPLETE; |
|---|
| 234 | } |
|---|
| 235 | |
|---|
| 236 | /* calculate max response msg size and allocate space */ |
|---|
| 237 | msg_p->max_resp_sz = PINT_encode_calc_max_size( |
|---|
| 238 | PINT_ENCODE_RESP, msg_p->req.op, msg_p->enc_type); |
|---|
| 239 | |
|---|
| 240 | |
|---|
| 241 | msg_p->encoded_resp_p = BMI_memalloc( |
|---|
| 242 | msg_p->svr_addr, msg_p->max_resp_sz, BMI_RECV); |
|---|
| 243 | |
|---|
| 244 | if (msg_p->encoded_resp_p == NULL) |
|---|
| 245 | { |
|---|
| 246 | js_p->error_code = -PVFS_ENOMEM; |
|---|
| 247 | return SM_ACTION_COMPLETE; |
|---|
| 248 | } |
|---|
| 249 | local_enc_and_alloc = 1; |
|---|
| 250 | } |
|---|
| 251 | |
|---|
| 252 | session_tag = PINT_util_get_next_tag(); |
|---|
| 253 | |
|---|
| 254 | /*store the session tag for this msgpair, so the msgpair completion */ |
|---|
| 255 | /*function can pass it to the caller of msgpairarray. */ |
|---|
| 256 | msg_p->session_tag = session_tag; |
|---|
| 257 | |
|---|
| 258 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, "%s: sm %p msgpair %d: " |
|---|
| 259 | "posting recv\n", __func__, smcb, i); |
|---|
| 260 | |
|---|
| 261 | /* post receive of response; job_id stored in recv_id */ |
|---|
| 262 | ret = job_bmi_recv(msg_p->svr_addr, |
|---|
| 263 | msg_p->encoded_resp_p, |
|---|
| 264 | msg_p->max_resp_sz, |
|---|
| 265 | session_tag, |
|---|
| 266 | BMI_PRE_ALLOC, |
|---|
| 267 | smcb, |
|---|
| 268 | i, |
|---|
| 269 | &msg_p->recv_status, |
|---|
| 270 | &msg_p->recv_id, |
|---|
| 271 | mop->params.job_context, |
|---|
| 272 | mop->params.job_timeout, |
|---|
| 273 | msg_p->req.hints); |
|---|
| 274 | if (ret == 0) |
|---|
| 275 | { |
|---|
| 276 | /* perform a quick test to see if the recv failed before posting |
|---|
| 277 | * the send; if it reports an error quickly then we can save the |
|---|
| 278 | * confusion of sending a request for which we can't recv a |
|---|
| 279 | * response |
|---|
| 280 | */ |
|---|
| 281 | ret = job_test(msg_p->recv_id, &tmp, NULL, |
|---|
| 282 | &msg_p->recv_status, 0, |
|---|
| 283 | mop->params.job_context); |
|---|
| 284 | } |
|---|
| 285 | |
|---|
| 286 | if ((ret < 0) || (ret == 1)) |
|---|
| 287 | { |
|---|
| 288 | /* it is impossible for this recv to complete at this point |
|---|
| 289 | * without errors; we haven't sent the request yet! |
|---|
| 290 | */ |
|---|
| 291 | assert(ret < 0 || msg_p->recv_status.error_code != 0); |
|---|
| 292 | if (ret < 0) |
|---|
| 293 | { |
|---|
| 294 | PVFS_perror_gossip("Post of receive failed", ret); |
|---|
| 295 | } |
|---|
| 296 | else |
|---|
| 297 | { |
|---|
| 298 | PVFS_perror_gossip("Receive immediately failed", |
|---|
| 299 | msg_p->recv_status.error_code); |
|---|
| 300 | } |
|---|
| 301 | |
|---|
| 302 | msg_p->recv_id = 0; |
|---|
| 303 | msg_p->send_id = 0; |
|---|
| 304 | |
|---|
| 305 | /* mark send as bad too and don't post it */ |
|---|
| 306 | msg_p->send_status.error_code = msg_p->recv_status.error_code; |
|---|
| 307 | msg_p->op_status = msg_p->recv_status.error_code; |
|---|
| 308 | mop->params.comp_ct -= 2; |
|---|
| 309 | |
|---|
| 310 | if (local_enc_and_alloc) |
|---|
| 311 | { |
|---|
| 312 | PINT_encode_release(&msg_p->encoded_req, PINT_ENCODE_REQ); |
|---|
| 313 | memset(&msg_p->encoded_req,0,sizeof(msg_p->encoded_req)); |
|---|
| 314 | BMI_memfree(msg_p->svr_addr,msg_p->encoded_resp_p, |
|---|
| 315 | msg_p->max_resp_sz, BMI_RECV); |
|---|
| 316 | msg_p->encoded_resp_p = NULL; |
|---|
| 317 | local_enc_and_alloc = 0; |
|---|
| 318 | } |
|---|
| 319 | |
|---|
| 320 | /* continue to send other array entries if possible */ |
|---|
| 321 | continue; |
|---|
| 322 | } |
|---|
| 323 | |
|---|
| 324 | /* if we reach here, the recv has been posted without failure, but |
|---|
| 325 | * has not completed yet |
|---|
| 326 | */ |
|---|
| 327 | assert(ret == 0); |
|---|
| 328 | |
|---|
| 329 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, "%s: sm %p msgpair %d: " |
|---|
| 330 | "posting send\n", __func__, smcb, i); |
|---|
| 331 | |
|---|
| 332 | /* post send of request; job_id stored in send_id */ |
|---|
| 333 | ret = job_bmi_send_list(msg_p->encoded_req.dest, |
|---|
| 334 | msg_p->encoded_req.buffer_list, |
|---|
| 335 | msg_p->encoded_req.size_list, |
|---|
| 336 | msg_p->encoded_req.list_count, |
|---|
| 337 | msg_p->encoded_req.total_size, |
|---|
| 338 | session_tag, |
|---|
| 339 | msg_p->encoded_req.buffer_type, |
|---|
| 340 | 1, |
|---|
| 341 | smcb, |
|---|
| 342 | mop->count+i, |
|---|
| 343 | &msg_p->send_status, |
|---|
| 344 | &msg_p->send_id, |
|---|
| 345 | mop->params.job_context, |
|---|
| 346 | mop->params.job_timeout, |
|---|
| 347 | msg_p->req.hints); |
|---|
| 348 | |
|---|
| 349 | if ((ret < 0) || |
|---|
| 350 | ((ret == 1) && (msg_p->send_status.error_code != 0))) |
|---|
| 351 | { |
|---|
| 352 | if (ret < 0) |
|---|
| 353 | { |
|---|
| 354 | PVFS_perror_gossip("Post of send failed", ret); |
|---|
| 355 | } |
|---|
| 356 | else |
|---|
| 357 | { |
|---|
| 358 | PVFS_perror_gossip("Send immediately failed", |
|---|
| 359 | msg_p->send_status.error_code); |
|---|
| 360 | } |
|---|
| 361 | |
|---|
| 362 | gossip_err_unless_quiet("Send error: cancelling recv.\n"); |
|---|
| 363 | |
|---|
| 364 | job_bmi_cancel(msg_p->recv_id, mop->params.job_context); |
|---|
| 365 | |
|---|
| 366 | /* we still have to wait for recv completion, so just decrement |
|---|
| 367 | * comp_ct by one and keep going |
|---|
| 368 | */ |
|---|
| 369 | msg_p->op_status = msg_p->send_status.error_code; |
|---|
| 370 | msg_p->send_id = 0; |
|---|
| 371 | mop->params.comp_ct--; |
|---|
| 372 | } |
|---|
| 373 | else if (ret == 1) |
|---|
| 374 | { |
|---|
| 375 | /* immediate completion */ |
|---|
| 376 | msg_p->send_id = 0; |
|---|
| 377 | /* decrement our count, since send is already done. */ |
|---|
| 378 | mop->params.comp_ct--; |
|---|
| 379 | } |
|---|
| 380 | /* else: successful post, no immediate completion */ |
|---|
| 381 | } |
|---|
| 382 | |
|---|
| 383 | if (mop->params.comp_ct == 0) |
|---|
| 384 | { |
|---|
| 385 | /* everything is completed already (could happen in some failure |
|---|
| 386 | * cases); jump straight to final completion function. |
|---|
| 387 | */ |
|---|
| 388 | js_p->error_code = MSGPAIRS_COMPLETE; |
|---|
| 389 | return SM_ACTION_COMPLETE; |
|---|
| 390 | } |
|---|
| 391 | |
|---|
| 392 | /* we are still waiting on operations to complete, next state |
|---|
| 393 | * transition will handle them |
|---|
| 394 | */ |
|---|
| 395 | return SM_ACTION_DEFERRED; |
|---|
| 396 | } |
|---|
| 397 | |
|---|
| 398 | static PINT_sm_action msgpairarray_post_retry( |
|---|
| 399 | struct PINT_smcb *smcb, job_status_s *js_p) |
|---|
| 400 | { |
|---|
| 401 | PINT_sm_msgarray_op *mop = PINT_sm_frame(smcb, PINT_FRAME_CURRENT); |
|---|
| 402 | job_id_t tmp_id; |
|---|
| 403 | |
|---|
| 404 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, "%s: sm %p, wait %d ms\n", |
|---|
| 405 | __func__, smcb, mop->params.retry_delay); |
|---|
| 406 | |
|---|
| 407 | js_p->error_code = 0; /* do not leak MSGPAIRS_RETRY through to wait */ |
|---|
| 408 | return job_req_sched_post_timer( |
|---|
| 409 | mop->params.retry_delay, |
|---|
| 410 | smcb, 0, js_p, &tmp_id, |
|---|
| 411 | mop->params.job_context); |
|---|
| 412 | } |
|---|
| 413 | |
|---|
| 414 | static PINT_sm_action msgpairarray_complete( |
|---|
| 415 | struct PINT_smcb *smcb, job_status_s *js_p) |
|---|
| 416 | { |
|---|
| 417 | PINT_sm_msgarray_op *mop = PINT_sm_frame(smcb, PINT_FRAME_CURRENT); |
|---|
| 418 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 419 | "%s: sm %p status_user_tag %d msgarray_count %d\n", |
|---|
| 420 | __func__, smcb, (int) js_p->status_user_tag, mop->count); |
|---|
| 421 | |
|---|
| 422 | |
|---|
| 423 | /* match operation with something in the msgpair array */ |
|---|
| 424 | /* the first N tags are receives, the second N are sends */ |
|---|
| 425 | assert(js_p->status_user_tag < mop->count*2); |
|---|
| 426 | |
|---|
| 427 | if (js_p->status_user_tag < mop->count) |
|---|
| 428 | { |
|---|
| 429 | PINT_sm_msgpair_state *msg_p = |
|---|
| 430 | &mop->msgarray[js_p->status_user_tag]; |
|---|
| 431 | |
|---|
| 432 | msg_p->recv_id = 0; |
|---|
| 433 | msg_p->recv_status = *js_p; |
|---|
| 434 | |
|---|
| 435 | /* save error (if we don't already have one) in op_status */ |
|---|
| 436 | if(msg_p->op_status == 0) |
|---|
| 437 | msg_p->op_status = msg_p->recv_status.error_code; |
|---|
| 438 | |
|---|
| 439 | if(msg_p->recv_status.error_code && msg_p->send_id != 0) |
|---|
| 440 | { |
|---|
| 441 | /* we got a receive error, but send is still pending. Cancel |
|---|
| 442 | * the send |
|---|
| 443 | */ |
|---|
| 444 | job_bmi_cancel(msg_p->send_id, mop->params.job_context); |
|---|
| 445 | } |
|---|
| 446 | } |
|---|
| 447 | else |
|---|
| 448 | { |
|---|
| 449 | PINT_sm_msgpair_state *msg_p = &mop->msgarray[ |
|---|
| 450 | js_p->status_user_tag - mop->count]; |
|---|
| 451 | |
|---|
| 452 | msg_p->send_id = 0; |
|---|
| 453 | msg_p->send_status = *js_p; |
|---|
| 454 | |
|---|
| 455 | /* save error (if we don't already have one) in op_status */ |
|---|
| 456 | if(msg_p->op_status == 0) |
|---|
| 457 | msg_p->op_status = msg_p->send_status.error_code; |
|---|
| 458 | |
|---|
| 459 | if(msg_p->send_status.error_code && msg_p->recv_id != 0) |
|---|
| 460 | { |
|---|
| 461 | /* we got a send error, but recv is still pending. Cancel |
|---|
| 462 | * the recv |
|---|
| 463 | */ |
|---|
| 464 | job_bmi_cancel(msg_p->recv_id, mop->params.job_context); |
|---|
| 465 | } |
|---|
| 466 | } |
|---|
| 467 | |
|---|
| 468 | /* decrement comp_ct until all operations have completed */ |
|---|
| 469 | if (--mop->params.comp_ct > 0) |
|---|
| 470 | { |
|---|
| 471 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 472 | " msgpairarray: %d operations remain\n", |
|---|
| 473 | mop->params.comp_ct); |
|---|
| 474 | return SM_ACTION_DEFERRED; |
|---|
| 475 | } |
|---|
| 476 | |
|---|
| 477 | assert(mop->params.comp_ct == 0); |
|---|
| 478 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 479 | " msgpairarray: all operations complete\n"); |
|---|
| 480 | |
|---|
| 481 | js_p->error_code = MSGPAIRS_COMPLETE; |
|---|
| 482 | return SM_ACTION_COMPLETE; |
|---|
| 483 | } |
|---|
| 484 | |
|---|
| 485 | static PINT_sm_action msgpairarray_completion_fn( |
|---|
| 486 | struct PINT_smcb *smcb, job_status_s *js_p) |
|---|
| 487 | { |
|---|
| 488 | PINT_sm_msgarray_op *mop = PINT_sm_frame(smcb, PINT_FRAME_CURRENT); |
|---|
| 489 | int ret = -PVFS_EINVAL, i = 0; |
|---|
| 490 | int need_retry = 0; |
|---|
| 491 | struct PINT_decoded_msg decoded_resp; |
|---|
| 492 | const char* server_string = NULL; |
|---|
| 493 | int server_type; |
|---|
| 494 | |
|---|
| 495 | /* response structure (decoded) */ |
|---|
| 496 | struct PVFS_server_resp *resp_p = NULL; |
|---|
| 497 | |
|---|
| 498 | js_p->error_code = 0; |
|---|
| 499 | |
|---|
| 500 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, "(%p) msgpairarray state: " |
|---|
| 501 | "completion_fn\n", smcb); |
|---|
| 502 | gossip_debug(GOSSIP_MIRROR_DEBUG,"Executing msgpairarray_completion_fn..\n"); |
|---|
| 503 | |
|---|
| 504 | for (i = 0; i < mop->count; i++) |
|---|
| 505 | { |
|---|
| 506 | PINT_sm_msgpair_state *msg_p = &mop->msgarray[i]; |
|---|
| 507 | assert(msg_p); |
|---|
| 508 | |
|---|
| 509 | /* |
|---|
| 510 | * Can take multiple trips through this function as we retry |
|---|
| 511 | * ones that failed. |
|---|
| 512 | */ |
|---|
| 513 | if (msg_p->complete) |
|---|
| 514 | continue; |
|---|
| 515 | |
|---|
| 516 | if (msg_p->op_status != 0) |
|---|
| 517 | { |
|---|
| 518 | char s[1024]; |
|---|
| 519 | PVFS_strerror_r(msg_p->op_status, s, sizeof(s)); |
|---|
| 520 | server_string = PINT_cached_config_map_addr( |
|---|
| 521 | msg_p->fs_id, msg_p->svr_addr, &server_type); |
|---|
| 522 | if(!server_string) |
|---|
| 523 | { |
|---|
| 524 | server_string = BMI_addr_rev_lookup(msg_p->svr_addr); |
|---|
| 525 | } |
|---|
| 526 | |
|---|
| 527 | gossip_err("Warning: msgpair failed to %s, will retry: %s\n", server_string, s); |
|---|
| 528 | |
|---|
| 529 | ++need_retry; |
|---|
| 530 | continue; |
|---|
| 531 | } |
|---|
| 532 | |
|---|
| 533 | ret = PINT_serv_decode_resp(msg_p->fs_id, |
|---|
| 534 | msg_p->encoded_resp_p, |
|---|
| 535 | &decoded_resp, |
|---|
| 536 | &msg_p->svr_addr, |
|---|
| 537 | msg_p->recv_status.actual_size, |
|---|
| 538 | &resp_p); |
|---|
| 539 | if (ret != 0) |
|---|
| 540 | { |
|---|
| 541 | PVFS_perror_gossip("msgpairarray decode error", ret); |
|---|
| 542 | msg_p->op_status = ret; |
|---|
| 543 | } |
|---|
| 544 | else |
|---|
| 545 | { |
|---|
| 546 | /* if we've made it this far, the server response status is |
|---|
| 547 | * meaningful, so we save it. |
|---|
| 548 | */ |
|---|
| 549 | msg_p->op_status = resp_p->status; |
|---|
| 550 | } |
|---|
| 551 | |
|---|
| 552 | /* NOTE: we call the function associated with each message, |
|---|
| 553 | * not just the one from the first array element. so |
|---|
| 554 | * there could in theory be different functions for each |
|---|
| 555 | * message (to handle different types of messages all in |
|---|
| 556 | * the same array). |
|---|
| 557 | */ |
|---|
| 558 | if (msg_p->comp_fn != NULL) |
|---|
| 559 | { |
|---|
| 560 | gossip_debug(GOSSIP_MIRROR_DEBUG,"\texecuting msg_p->comp_fn..\n"); |
|---|
| 561 | /* If we call the completion function, store the result on |
|---|
| 562 | * a per message pair basis. Also store some non-zero |
|---|
| 563 | * (failure) value in js_p->error_code if we see one. |
|---|
| 564 | */ |
|---|
| 565 | msg_p->op_status = msg_p->comp_fn(smcb, resp_p, i); |
|---|
| 566 | if (msg_p->op_status != 0) |
|---|
| 567 | { |
|---|
| 568 | js_p->error_code = msg_p->op_status; |
|---|
| 569 | } |
|---|
| 570 | |
|---|
| 571 | /* even if we see a failure, continue to process with the |
|---|
| 572 | * completion function. -- RobR |
|---|
| 573 | */ |
|---|
| 574 | } |
|---|
| 575 | else if (resp_p->status != 0) |
|---|
| 576 | { |
|---|
| 577 | /* no comp_fn specified and status non-zero */ |
|---|
| 578 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 579 | "notice: msgpairarray_complete: error %d " |
|---|
| 580 | "from server %d\n", resp_p->status, i); |
|---|
| 581 | |
|---|
| 582 | /* save a non-zero status to return if we see one */ |
|---|
| 583 | js_p->error_code = resp_p->status; |
|---|
| 584 | |
|---|
| 585 | /* If we don't have a completion function, there is no point |
|---|
| 586 | * in continuing to process after seeing a failure. |
|---|
| 587 | */ |
|---|
| 588 | if (js_p->error_code) |
|---|
| 589 | { |
|---|
| 590 | break; |
|---|
| 591 | } |
|---|
| 592 | } |
|---|
| 593 | |
|---|
| 594 | /* free all the resources that we used to send and receive. */ |
|---|
| 595 | ret = PINT_serv_free_msgpair_resources( |
|---|
| 596 | &msg_p->encoded_req, msg_p->encoded_resp_p, &decoded_resp, |
|---|
| 597 | &msg_p->svr_addr, msg_p->max_resp_sz); |
|---|
| 598 | if (ret) |
|---|
| 599 | { |
|---|
| 600 | PVFS_perror_gossip("Failed to free msgpair resources", ret); |
|---|
| 601 | js_p->error_code = ret; |
|---|
| 602 | return SM_ACTION_COMPLETE; |
|---|
| 603 | } |
|---|
| 604 | |
|---|
| 605 | memset(&msg_p->encoded_req,0,sizeof(msg_p->encoded_req)); |
|---|
| 606 | msg_p->encoded_resp_p = NULL; |
|---|
| 607 | msg_p->max_resp_sz = 0; |
|---|
| 608 | |
|---|
| 609 | /* |
|---|
| 610 | mark that this msgpair has been completed and should not be |
|---|
| 611 | retried in the case of possible future retries |
|---|
| 612 | */ |
|---|
| 613 | msg_p->complete = 1; |
|---|
| 614 | |
|---|
| 615 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, "%s: sm %p msgpair %d " |
|---|
| 616 | "marked complete\n", __func__, smcb, i); |
|---|
| 617 | }/*end for*/ |
|---|
| 618 | |
|---|
| 619 | if (need_retry) { |
|---|
| 620 | /* |
|---|
| 621 | * We only retry msgpairs that are not yet complete. Factor |
|---|
| 622 | * of two since they are pairs. If over the count, do not |
|---|
| 623 | * retry, just return one of the error codes. |
|---|
| 624 | */ |
|---|
| 625 | mop->params.comp_ct = 0; |
|---|
| 626 | js_p->error_code = 0; |
|---|
| 627 | for (i=0; i < mop->count; i++) { |
|---|
| 628 | |
|---|
| 629 | PINT_sm_msgpair_state *msg_p = &mop->msgarray[i]; |
|---|
| 630 | |
|---|
| 631 | if (msg_p->complete) |
|---|
| 632 | continue; |
|---|
| 633 | |
|---|
| 634 | if (msg_p->retry_flag == PVFS_MSGPAIR_RETRY |
|---|
| 635 | && PVFS_ERROR_CLASS(-msg_p->op_status) == PVFS_ERROR_BMI |
|---|
| 636 | && msg_p->retry_count < mop->params.retry_limit) { |
|---|
| 637 | |
|---|
| 638 | ++msg_p->retry_count; |
|---|
| 639 | mop->params.comp_ct += 2; |
|---|
| 640 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 641 | "*** %s: msgpair %d failed, retry %d\n", |
|---|
| 642 | __func__, i, msg_p->retry_count); |
|---|
| 643 | if(msg_p->op_status == -BMI_ECANCEL) |
|---|
| 644 | { |
|---|
| 645 | /* if the error code indicates cancel, then skip the |
|---|
| 646 | * delay. We have probably already been waiting a while |
|---|
| 647 | */ |
|---|
| 648 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 649 | "*** %s: msgpair skipping retry delay.\n", __func__); |
|---|
| 650 | js_p->error_code = MSGPAIRS_RETRY_NODELAY; |
|---|
| 651 | } |
|---|
| 652 | else |
|---|
| 653 | { |
|---|
| 654 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 655 | "*** %s: msgpair retrying after delay.\n", __func__); |
|---|
| 656 | js_p->error_code = MSGPAIRS_RETRY; |
|---|
| 657 | } |
|---|
| 658 | |
|---|
| 659 | } else { |
|---|
| 660 | char s[1024]; |
|---|
| 661 | server_string = PINT_cached_config_map_addr( |
|---|
| 662 | msg_p->fs_id, msg_p->svr_addr, &server_type); |
|---|
| 663 | if(!server_string) |
|---|
| 664 | { |
|---|
| 665 | server_string = "[UNKNOWN]"; |
|---|
| 666 | } |
|---|
| 667 | PVFS_strerror_r(msg_p->op_status, s, sizeof(s)); |
|---|
| 668 | gossip_err_unless_quiet("*** %s: msgpair to server %s failed: %s\n", |
|---|
| 669 | __func__, server_string, s); |
|---|
| 670 | if(msg_p->retry_flag != PVFS_MSGPAIR_RETRY) |
|---|
| 671 | { |
|---|
| 672 | gossip_err_unless_quiet("*** No retries requested.\n"); |
|---|
| 673 | } |
|---|
| 674 | else if(PVFS_ERROR_CLASS(-msg_p->op_status) != |
|---|
| 675 | PVFS_ERROR_BMI) |
|---|
| 676 | { |
|---|
| 677 | gossip_err_unless_quiet("*** Non-BMI failure.\n"); |
|---|
| 678 | } |
|---|
| 679 | else |
|---|
| 680 | { |
|---|
| 681 | gossip_err_unless_quiet("*** Out of retries.\n"); |
|---|
| 682 | } |
|---|
| 683 | if (js_p->error_code == 0) |
|---|
| 684 | js_p->error_code = msg_p->op_status; |
|---|
| 685 | } |
|---|
| 686 | |
|---|
| 687 | } |
|---|
| 688 | } |
|---|
| 689 | return SM_ACTION_COMPLETE; |
|---|
| 690 | } |
|---|
| 691 | |
|---|
| 692 | static PINT_sm_action msgpairarray_done( |
|---|
| 693 | struct PINT_smcb *smcb, job_status_s *js_p) |
|---|
| 694 | { |
|---|
| 695 | int task_id, error_code, remaining; |
|---|
| 696 | PINT_sm_pop_frame(smcb, &task_id, &error_code, &remaining); |
|---|
| 697 | return SM_ACTION_COMPLETE; |
|---|
| 698 | } |
|---|
| 699 | |
|---|
| 700 | /********************************************************************* |
|---|
| 701 | * helper functions used in conjunction with state machine defined above |
|---|
| 702 | */ |
|---|
| 703 | |
|---|
| 704 | int PINT_msgpairarray_init( |
|---|
| 705 | PINT_sm_msgarray_op *op, |
|---|
| 706 | int count) |
|---|
| 707 | { |
|---|
| 708 | op->msgarray = (PINT_sm_msgpair_state *)malloc( |
|---|
| 709 | count * sizeof(PINT_sm_msgpair_state)); |
|---|
| 710 | if(!op->msgarray) |
|---|
| 711 | { |
|---|
| 712 | return -PVFS_ENOMEM; |
|---|
| 713 | } |
|---|
| 714 | memset(op->msgarray, 0, (count * sizeof(PINT_sm_msgpair_state))); |
|---|
| 715 | op->count = count; |
|---|
| 716 | |
|---|
| 717 | return 0; |
|---|
| 718 | } |
|---|
| 719 | |
|---|
| 720 | /* we pass in a pointer to the array so that we can set it to NULL */ |
|---|
| 721 | void PINT_msgpairarray_destroy( |
|---|
| 722 | PINT_sm_msgarray_op *op) |
|---|
| 723 | { |
|---|
| 724 | if(op->msgarray && (&op->msgpair) != op->msgarray) |
|---|
| 725 | { |
|---|
| 726 | free(op->msgarray); |
|---|
| 727 | } |
|---|
| 728 | op->msgarray = NULL; |
|---|
| 729 | op->count = 0; |
|---|
| 730 | } |
|---|
| 731 | |
|---|
| 732 | int PINT_msgarray_status(PINT_sm_msgarray_op *op) |
|---|
| 733 | { |
|---|
| 734 | int i; |
|---|
| 735 | for (i = 0; i < op->count; i++) |
|---|
| 736 | { |
|---|
| 737 | if (op->msgarray[i].op_status != 0) |
|---|
| 738 | { |
|---|
| 739 | return op->msgarray[i].op_status; |
|---|
| 740 | } |
|---|
| 741 | } |
|---|
| 742 | return 0; |
|---|
| 743 | } |
|---|
| 744 | |
|---|
| 745 | int PINT_serv_decode_resp(PVFS_fs_id fs_id, |
|---|
| 746 | void *encoded_resp_p, |
|---|
| 747 | struct PINT_decoded_msg *decoded_resp_p, |
|---|
| 748 | PVFS_BMI_addr_t *svr_addr_p, |
|---|
| 749 | int actual_resp_sz, |
|---|
| 750 | struct PVFS_server_resp **resp_out_pp) |
|---|
| 751 | { |
|---|
| 752 | int ret = -1, server_type = 0; |
|---|
| 753 | const char *server_string; |
|---|
| 754 | |
|---|
| 755 | ret = PINT_decode(encoded_resp_p, PINT_DECODE_RESP, |
|---|
| 756 | decoded_resp_p, /* holds data on decoded resp */ |
|---|
| 757 | *svr_addr_p, actual_resp_sz); |
|---|
| 758 | if (ret > -1) |
|---|
| 759 | { |
|---|
| 760 | *resp_out_pp = (struct PVFS_server_resp *)decoded_resp_p->buffer; |
|---|
| 761 | if ((*resp_out_pp)->op == PVFS_SERV_PROTO_ERROR) |
|---|
| 762 | { |
|---|
| 763 | |
|---|
| 764 | gossip_err("Error: server does not seem to understand " |
|---|
| 765 | "the protocol that this client is using.\n"); |
|---|
| 766 | gossip_err(" Please check server logs for more " |
|---|
| 767 | "information.\n"); |
|---|
| 768 | |
|---|
| 769 | if (fs_id != PVFS_FS_ID_NULL) |
|---|
| 770 | { |
|---|
| 771 | server_string = PINT_cached_config_map_addr( |
|---|
| 772 | fs_id, *svr_addr_p, &server_type); |
|---|
| 773 | gossip_err(" Server: %s.\n", server_string); |
|---|
| 774 | } |
|---|
| 775 | else |
|---|
| 776 | { |
|---|
| 777 | gossip_err(" Server: unknown; probably an error " |
|---|
| 778 | "contacting server listed in pvfs2tab " |
|---|
| 779 | "file.\n"); |
|---|
| 780 | } |
|---|
| 781 | return(-EPROTONOSUPPORT); |
|---|
| 782 | } |
|---|
| 783 | } |
|---|
| 784 | return ret; |
|---|
| 785 | } |
|---|
| 786 | |
|---|
| 787 | int PINT_serv_free_msgpair_resources( |
|---|
| 788 | struct PINT_encoded_msg *encoded_req_p, |
|---|
| 789 | void *encoded_resp_p, |
|---|
| 790 | struct PINT_decoded_msg *decoded_resp_p, |
|---|
| 791 | PVFS_BMI_addr_t *svr_addr_p, |
|---|
| 792 | int max_resp_sz) |
|---|
| 793 | { |
|---|
| 794 | int ret = -PVFS_EINVAL; |
|---|
| 795 | |
|---|
| 796 | if (encoded_req_p && decoded_resp_p && svr_addr_p) |
|---|
| 797 | { |
|---|
| 798 | PINT_encode_release(encoded_req_p, PINT_ENCODE_REQ); |
|---|
| 799 | memset(encoded_req_p,0,sizeof(*encoded_req_p)); |
|---|
| 800 | |
|---|
| 801 | PINT_decode_release(decoded_resp_p, PINT_DECODE_RESP); |
|---|
| 802 | memset(decoded_resp_p,0,sizeof(*decoded_resp_p)); |
|---|
| 803 | |
|---|
| 804 | BMI_memfree(*svr_addr_p, encoded_resp_p, max_resp_sz, BMI_RECV); |
|---|
| 805 | encoded_resp_p = NULL; |
|---|
| 806 | |
|---|
| 807 | ret = 0; |
|---|
| 808 | } |
|---|
| 809 | return ret; |
|---|
| 810 | } |
|---|
| 811 | |
|---|
| 812 | /* PINT_serv_msgpair_array_resolve_addrs() |
|---|
| 813 | * |
|---|
| 814 | * fills in BMI address of server for each entry in the msgpair array, |
|---|
| 815 | * based on the handle and fsid |
|---|
| 816 | * |
|---|
| 817 | * returns 0 on success, -PVFS_error on failure |
|---|
| 818 | */ |
|---|
| 819 | int PINT_serv_msgpairarray_resolve_addrs( |
|---|
| 820 | PINT_sm_msgarray_op *mop) |
|---|
| 821 | { |
|---|
| 822 | int i = 0; |
|---|
| 823 | int ret = -PVFS_EINVAL; |
|---|
| 824 | |
|---|
| 825 | if ((mop->count > 0) && mop->msgarray) |
|---|
| 826 | { |
|---|
| 827 | for(i = 0; i < mop->count; i++) |
|---|
| 828 | { |
|---|
| 829 | PINT_sm_msgpair_state *msg_p = &mop->msgarray[i]; |
|---|
| 830 | assert(msg_p); |
|---|
| 831 | |
|---|
| 832 | ret = PINT_cached_config_map_to_server( |
|---|
| 833 | &msg_p->svr_addr, msg_p->handle, msg_p->fs_id); |
|---|
| 834 | |
|---|
| 835 | if (ret != 0) |
|---|
| 836 | { |
|---|
| 837 | gossip_err("Failed to map server address to handle\n"); |
|---|
| 838 | break; |
|---|
| 839 | } |
|---|
| 840 | |
|---|
| 841 | gossip_debug(GOSSIP_MSGPAIR_DEBUG, |
|---|
| 842 | " mapped handle %llu to server %lld\n", |
|---|
| 843 | llu(msg_p->handle), lld(msg_p->svr_addr)); |
|---|
| 844 | } |
|---|
| 845 | } |
|---|
| 846 | return ret; |
|---|
| 847 | } |
|---|
| 848 | |
|---|
| 849 | /* |
|---|
| 850 | * Local variables: |
|---|
| 851 | * mode: c |
|---|
| 852 | * c-indent-level: 4 |
|---|
| 853 | * c-basic-offset: 4 |
|---|
| 854 | * End: |
|---|
| 855 | * |
|---|
| 856 | * vim: ft=c ts=8 sts=4 sw=4 expandtab |
|---|
| 857 | */ |
|---|
| 858 | |
|---|