libjf API reference guide

Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

jf_journal_recovery.c

Go to the documentation of this file.
00001 /* 00002 * Copyright 2005 Tiian 00003 * {In real life Tiian is Christian Ferrari} 00004 * This file is part of "libjf" package. 00005 * 00006 * "libjf" is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU Lesser General Public License as published by 00008 * the Free Software Foundation; either version 2.1 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * "libjf" is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser General Public License 00017 * along with ; if not, write to the Free Software 00018 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00019 */ 00020 #include <jf/jf_config.h> 00021 00022 00023 00024 #ifdef HAVE_STDLIB_H 00025 # include <stdlib.h> 00026 #endif 00027 00028 #include <jf/jf_journal_recovery.h> 00029 #include <jf/jf_utils.h> 00030 #include <jf/jf_crash_simul.h> 00031 #include <jf_file.h> 00032 00033 00034 00035 /* set module trace flag */ 00036 #ifdef JF_TRACE_MODULE 00037 # undef JF_TRACE_MODULE 00038 #endif /* JF_TRACE_MODULE */ 00039 #define JF_TRACE_MODULE JF_TRACE_MOD_LIB_JOURNAL_RECOVERY 00040 00041 00042 00043 void jf_journal_record_reset(struct jf_journal_record_s *jr) 00044 { 00045 jr->redo_code = JF_JOURNAL_OP_CODE_NULL; 00046 jr->redo_data = NULL; 00047 jr->redo_data_alloc = 0; 00048 jr->undo_code = JF_JOURNAL_OP_CODE_NULL; 00049 jr->undo_data = NULL; 00050 jr->undo_data_alloc = 0; 00051 } 00052 00053 00054 00055 void jf_journal_record_destroy(struct jf_journal_record_s *jr) 00056 { 00057 if (jr->redo_data != NULL) { 00058 free(jr->redo_data); 00059 jr->redo_data = NULL; 00060 } 00061 if (jr->undo_data != NULL) { 00062 free(jr->undo_data); 00063 jr->undo_data = NULL; 00064 } 00065 jf_journal_record_reset(jr); 00066 } 00067 00068 00069 00070 int jf_journal_analyze(const char *path, uint32_t flags, FILE *out_stream) 00071 { 00072 enum Exception { FOPEN_ERROR 00073 , JOURNAL_LOAD 00074 , FSEEK_ERROR 00075 , JOURNAL_SCAN 00076 , NONE } excp; 00077 int ret_cod = JF_RC_INTERNAL_ERROR; 00078 FILE *jrn_stream = NULL; 00079 00080 JF_TRACE(("jf_journal_analyze\n")); 00081 TRY { 00082 jf_journal_t journal; 00083 00084 if (out_stream == NULL) 00085 out_stream = stdout; 00086 00087 /* open journal stream */ 00088 if (NULL == (jrn_stream = fopen(path, "r+b"))) 00089 THROW(FOPEN_ERROR); 00090 00091 /* reset journal object */ 00092 jf_journal_reset(&journal); 00093 00094 /* load journal content (static data and control records) */ 00095 ret_cod = jf_journal_load(&journal, jrn_stream); 00096 if (JF_RC_OK != ret_cod) 00097 THROW(JOURNAL_LOAD); 00098 00099 if (flags & JF_JOURNAL_ANALYZE_TRACE) { 00100 fprintf(out_stream, 00101 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" 00102 "<journal>\n"); 00103 jf_journal_trace(&journal, "", out_stream); 00104 } 00105 00106 /* repos stream to first interesting record */ 00107 if (flags & JF_JOURNAL_ANALYZE_RECOVERY) { 00108 /* retrieve last_pos */ 00109 jf_journal_file_t *jrn_jfile = 00110 jf_journal_file_tab_get_jfile( 00111 &(journal.file_table), 00112 JF_JOURNAL_JOURNAL_FILE_ID); 00113 /* skip a piece of journal */ 00114 if (0 != fseeko( 00115 jrn_stream, jf_journal_file_get_last_pos( 00116 jrn_jfile), 00117 SEEK_SET)) 00118 THROW(FSEEK_ERROR); 00119 } /* if (flags & JF_JOURNAL_ANALYZE_RECOVERY) */ 00120 00121 ret_cod = jf_journal_scan(&journal, JF_JOURNAL_GLOBAL_FILE_ID, 00122 flags, TRUE, out_stream); 00123 if (JF_RC_OK != ret_cod) 00124 THROW(JOURNAL_SCAN); 00125 00126 if (flags & JF_JOURNAL_ANALYZE_TRACE) 00127 fprintf(out_stream, "</journal>\n"); 00128 00129 THROW(NONE); 00130 } CATCH { 00131 switch (excp) { 00132 case FOPEN_ERROR: 00133 ret_cod = JF_RC_FOPEN_ERROR; 00134 break; 00135 case JOURNAL_LOAD: 00136 break; 00137 case FSEEK_ERROR: 00138 break; 00139 case JOURNAL_SCAN: 00140 break; 00141 case NONE: 00142 ret_cod = JF_RC_OK; 00143 break; 00144 default: 00145 ret_cod = JF_RC_INTERNAL_ERROR; 00146 } /* switch (excp) */ 00147 00148 /* release stream */ 00149 if (jrn_stream != NULL && 0 != fclose(jrn_stream) && 00150 ret_cod >= JF_RC_OK) 00151 ret_cod = JF_RC_FCLOSE_ERROR; 00152 00153 } /* TRY-CATCH */ 00154 JF_TRACE(("jf_journal_analyze/excp=%d/ret_cod=%d/errno=%d\n", 00155 excp, ret_cod, errno)); 00156 return ret_cod; 00157 } 00158 00159 00160 00161 int jf_journal_scan(jf_journal_t *journal, jf_word_t file_id, uint32_t flags, 00162 int forward, FILE *out_stream) 00163 { 00164 enum Exception { REOPEN_FILES 00165 , FTELL_ERROR1 00166 , FTELL_ERROR2 00167 , SCAN_SEARCH 00168 , SCAN_REDO 00169 , SCAN_UNDO 00170 , INVALID_STATUS 00171 , TRACE_RECORD 00172 , INTERNAL_ERROR 00173 , ROLLBACK_ERROR 00174 , FTELL_ERROR3 00175 , FSEEK_ERROR 00176 , NONE } excp; 00177 int ret_cod = JF_RC_INTERNAL_ERROR; 00178 00179 struct jf_journal_record_s jr; 00180 jf_journal_scan_status_t status = 00181 forward ? JF_SCAN_SEARCH : JF_SCAN_UNDO; 00182 00183 JF_TRACE(("jf_journal_scan: file_id = " JF_WORD_T_FORMAT "\n", 00184 file_id)); 00185 00186 TRY { 00187 jf_offset_t last_sync; 00188 00189 FILE *jrn_stream = jf_journal_get_stream(journal); 00190 00191 /* reset record object */ 00192 jf_journal_record_reset(&jr); 00193 00194 /* re-open files opened at last journal sync */ 00195 if (JF_RC_OK != (ret_cod = jf_journal_reopen_files(journal))) 00196 THROW(REOPEN_FILES); 00197 00198 /* assuming current file pointer position as a "sync" 00199 * position */ 00200 if (0 > (last_sync = ftello(jrn_stream))) 00201 THROW(FTELL_ERROR1); 00202 00203 if (flags & JF_JOURNAL_ANALYZE_TRACE) 00204 fprintf(out_stream, " <records>\n"); 00205 00206 while (TRUE) { 00207 jf_offset_t journal_record_offset = 0; 00208 00209 if ((flags & JF_JOURNAL_ANALYZE_TRACE) && 00210 (0 > (journal_record_offset = ftello(jrn_stream)))) 00211 THROW(FTELL_ERROR2); 00212 00213 switch (status) { 00214 case JF_SCAN_SEARCH: 00215 ret_cod = jf_journal_scan_search( 00216 journal, &jr, &status, last_sync, 00217 forward, flags); 00218 if (ret_cod != JF_RC_OK && 00219 ret_cod != JF_RC_EOF) 00220 THROW(SCAN_SEARCH); 00221 break; 00222 case JF_SCAN_REDO: 00223 ret_cod = jf_journal_scan_redo( 00224 journal, &jr, &status); 00225 if (ret_cod != JF_RC_OK && 00226 ret_cod != JF_RC_EOF) 00227 THROW(SCAN_REDO); 00228 break; 00229 case JF_SCAN_UNDO: 00230 ret_cod = jf_journal_scan_undo( 00231 journal, file_id, &jr, &status); 00232 if (ret_cod != JF_RC_OK && 00233 ret_cod != JF_RC_EOF) 00234 THROW(SCAN_UNDO); 00235 break; 00236 case JF_SCAN_END: 00237 break; 00238 default: 00239 THROW(INVALID_STATUS); 00240 } /* switch (status) */ 00241 00242 /* break scan loop */ 00243 if (JF_RC_EOF == ret_cod) 00244 break; 00245 /* trace journal record */ 00246 if (flags & JF_JOURNAL_ANALYZE_TRACE && 00247 JF_RC_OK != ( 00248 ret_cod = jf_journal_trace_record( 00249 journal, &jr, 00250 journal_record_offset, 00251 out_stream, flags))) 00252 THROW(TRACE_RECORD); 00253 } /* while (TRUE) */ 00254 00255 if (flags & JF_JOURNAL_ANALYZE_TRACE) 00256 fprintf(out_stream, " </records>\n"); 00257 00258 /* repos journal stream */ 00259 if (0 != fseeko(jrn_stream, last_sync, SEEK_SET)) 00260 THROW(FSEEK_ERROR); 00261 00262 THROW(NONE); 00263 } CATCH { 00264 switch (excp) { 00265 case REOPEN_FILES: 00266 break; 00267 case FTELL_ERROR1: 00268 case FTELL_ERROR2: 00269 case FTELL_ERROR3: 00270 ret_cod = JF_RC_FTELL_ERROR; 00271 break; 00272 case SCAN_SEARCH: 00273 case SCAN_REDO: 00274 case SCAN_UNDO: 00275 break; 00276 case INVALID_STATUS: 00277 ret_cod = JF_RC_INTERNAL_ERROR; 00278 break; 00279 case TRACE_RECORD: 00280 break; 00281 case INTERNAL_ERROR: 00282 ret_cod = JF_RC_INTERNAL_ERROR; 00283 break; 00284 case ROLLBACK_ERROR: 00285 break; 00286 case FSEEK_ERROR: 00287 ret_cod = JF_RC_FSEEK_ERROR; 00288 break; 00289 case NONE: 00290 ret_cod = JF_RC_OK; 00291 break; 00292 default: 00293 ret_cod = JF_RC_INTERNAL_ERROR; 00294 } /* switch (excp) */ 00295 00296 /* release journal record object */ 00297 jf_journal_record_destroy(&jr); 00298 00299 } /* TRY-CATCH */ 00300 JF_TRACE(("jf_journal_scan/excp=%d/ret_cod=%d/errno=%d\n", 00301 excp, ret_cod, errno)); 00302 return ret_cod; 00303 } 00304 00305 00306 00307 int jf_journal_scan_search(jf_journal_t *journal, 00308 struct jf_journal_record_s *jr, 00309 jf_journal_scan_status_t *status, 00310 jf_offset_t last_sync, int forward, uint32_t flags) 00311 { 00312 enum Exception { END_OF_FILE 00313 , FETCH_RECORD 00314 , SKIP_RECORD 00315 , FSEEK_ERROR1 00316 , FSEEK_ERROR2 00317 , SET_ALL_IN_CACHE 00318 , NONE } excp; 00319 int ret_cod = JF_RC_INTERNAL_ERROR; 00320 00321 JF_TRACE(("jf_journal_scan_search\n")); 00322 TRY { 00323 FILE *jrn_stream = jf_journal_get_stream(journal); 00324 jf_word_t ctrl_code, id; 00325 00326 ret_cod = jf_journal_fetch_record(journal, jr, forward); 00327 if (ret_cod == JF_RC_EOF) { 00328 THROW(END_OF_FILE); 00329 } else if (ret_cod != JF_RC_OK) 00330 THROW(FETCH_RECORD); 00331 00332 if (!(flags & JF_JOURNAL_ANALYZE_RECOVERY)) 00333 THROW(SKIP_RECORD); 00334 00335 /* retrieve control code */ 00336 if (forward) { 00337 ctrl_code = jr->redo_code & JF_JOURNAL_OP_MASK; 00338 id = (jr->redo_code & journal->file_id_mask) >> 00339 journal->file_id_mask_shift; 00340 } else { 00341 ctrl_code = jr->undo_code & JF_JOURNAL_OP_MASK; 00342 id = (jr->undo_code & journal->file_id_mask) >> 00343 journal->file_id_mask_shift; 00344 } /* if (forward) */ 00345 switch (ctrl_code) { 00346 case JF_JOURNAL_OP_CODE_COMMIT: 00347 /* come back to last sync point */ 00348 JF_TRACE(("jf_journal_scan_search: " 00349 "found COMMIT record\n")); 00350 if (0 != fseeko(jrn_stream, last_sync, 00351 SEEK_SET)) 00352 THROW(FSEEK_ERROR1); 00353 if (forward) 00354 *status = JF_SCAN_REDO; 00355 else 00356 *status = JF_SCAN_UNDO; 00357 break; 00358 case JF_JOURNAL_OP_CODE_ROLLBACK: 00359 /* move back to previous record */ 00360 JF_TRACE(("jf_journal_scan_search: " 00361 "found ROLLBACK record\n")); 00362 if (0 != fseeko( 00363 jrn_stream, 00364 -((jf_offset_t)sizeof(jf_word_t)), 00365 SEEK_CUR)) 00366 THROW(FSEEK_ERROR2); 00367 *status = JF_SCAN_UNDO; 00368 break; 00369 default: /* nothing to do */ 00370 break; 00371 } /* switch (ctrl_code) */ 00372 00373 THROW(NONE); 00374 } CATCH { 00375 switch (excp) { 00376 case END_OF_FILE: 00377 break; 00378 case FETCH_RECORD: 00379 break; 00380 case SKIP_RECORD: 00381 ret_cod = JF_RC_OK; 00382 break; 00383 case FSEEK_ERROR1: 00384 case FSEEK_ERROR2: 00385 ret_cod = JF_RC_FSEEK_ERROR; 00386 break; 00387 case SET_ALL_IN_CACHE: 00388 break; 00389 case NONE: 00390 ret_cod = JF_RC_OK; 00391 break; 00392 default: 00393 ret_cod = JF_RC_INTERNAL_ERROR; 00394 } /* switch (excp) */ 00395 } /* TRY-CATCH */ 00396 JF_TRACE(("jf_journal_scan_search/excp=%d/ret_cod=%d/" 00397 "errno=%d\n", excp, ret_cod, errno)); 00398 return ret_cod; 00399 } 00400 00401 00402 00403 int jf_journal_scan_redo(jf_journal_t *journal, 00404 struct jf_journal_record_s *jr, 00405 jf_journal_scan_status_t *status) 00406 { 00407 enum Exception { END_OF_FILE 00408 , FETCH_RECORD 00409 , INVALID_STATUS 00410 , APPLY_CHANGES 00411 , NONE } excp; 00412 int ret_cod = JF_RC_INTERNAL_ERROR; 00413 00414 JF_TRACE(("jf_journal_scan_redo\n")); 00415 TRY { 00416 jf_word_t ctrl_code; 00417 00418 ret_cod = jf_journal_fetch_record(journal, jr, TRUE); 00419 if (ret_cod == JF_RC_EOF) { 00420 THROW(END_OF_FILE); 00421 } else if (ret_cod != JF_RC_OK) 00422 THROW(FETCH_RECORD); 00423 /* retrieve control code */ 00424 ctrl_code = jr->redo_code & JF_JOURNAL_OP_MASK; 00425 switch (ctrl_code) { 00426 case JF_JOURNAL_OP_CODE_COMMIT: 00427 break; /* nothing to do */ 00428 case JF_JOURNAL_OP_CODE_ROLLBACK: 00429 THROW(INVALID_STATUS); 00430 break; 00431 default: /* apply changes */ 00432 ret_cod = jf_journal_apply_changes(journal, jr); 00433 if (JF_RC_OK != ret_cod) 00434 THROW(APPLY_CHANGES); 00435 break; 00436 } /* switch (ctrl_code) */ 00437 00438 THROW(NONE); 00439 } CATCH { 00440 switch (excp) { 00441 case END_OF_FILE: 00442 break; 00443 case FETCH_RECORD: 00444 break; 00445 case INVALID_STATUS: 00446 ret_cod = JF_RC_INTERNAL_ERROR; 00447 break; 00448 case APPLY_CHANGES: 00449 break; 00450 case NONE: 00451 ret_cod = JF_RC_OK; 00452 break; 00453 default: 00454 ret_cod = JF_RC_INTERNAL_ERROR; 00455 } /* switch (excp) */ 00456 } /* TRY-CATCH */ 00457 JF_TRACE(("jf_journal_scan_redo/excp=%d/ret_cod=%d/errno=%d\n", 00458 excp, ret_cod, errno)); 00459 return ret_cod; 00460 } 00461 00462 00463 00464 int jf_journal_scan_undo(jf_journal_t *journal, jf_word_t rec_file_id, 00465 struct jf_journal_record_s *jr, 00466 jf_journal_scan_status_t *status) 00467 { 00468 enum Exception { END_OF_FILE1 00469 , FETCH_RECORD 00470 , SET_ALL_SYNC1 00471 , FILE_SET_STATUS0 00472 , FILE_SET_STATUS1 00473 , END_OF_FILE2 00474 , END_OF_FILE3 00475 , FILE_SET_ALL_IN_CACHE 00476 , INVALID_STATUS 00477 , FSEEK_ERROR1 00478 , SET_ALL_SYNC2 00479 , FILE_SET_STATUS2 00480 , END_OF_FILE4 00481 , END_OF_FILE5 00482 , FSEEK_ERROR2 00483 , SKIP_RECORD 00484 , APPLY_CHANGES 00485 , NONE } excp; 00486 int ret_cod = JF_RC_INTERNAL_ERROR; 00487 00488 JF_TRACE(("jf_journal_scan_undo\n")); 00489 TRY { 00490 jf_word_t ctrl_code; 00491 jf_word_t jr_file_id; 00492 jf_journal_file_t *jfile = NULL, *rec_file = NULL; 00493 FILE *jrn_stream = NULL; 00494 00495 ret_cod = jf_journal_fetch_record(journal, jr, FALSE); 00496 if (ret_cod == JF_RC_EOF) { 00497 THROW(END_OF_FILE1); 00498 } else if (ret_cod != JF_RC_OK) 00499 THROW(FETCH_RECORD); 00500 /* retrieve control code */ 00501 00502 ctrl_code = jr->undo_code & JF_JOURNAL_OP_MASK; 00503 jr_file_id = (jr->undo_code & journal->file_id_mask) >> 00504 journal->file_id_mask_shift; 00505 jfile = jf_journal_file_tab_get_jfile( 00506 &(journal->file_table), jr_file_id); 00507 00508 JF_TRACE(("jf_journal_scan_undo: " 00509 "jr_file_id = " JF_WORD_T_FORMAT ", " 00510 "rec_file_id = " JF_WORD_T_FORMAT "\n", 00511 jr_file_id, rec_file_id)); 00512 00513 switch (ctrl_code) { 00514 case JF_JOURNAL_OP_CODE_COMMIT: 00515 JF_TRACE(("jf_journal_scan_undo: " 00516 "JF_JOURNAL_OP_CODE_COMMIT\n")); 00517 if (jr_file_id == JF_JOURNAL_GLOBAL_FILE_ID) { 00518 JF_TRACE(("jf_journal_scan_undo: " 00519 "JF_JOURNAL_OP_CODE_COMMIT, " 00520 "jr_file_id == " 00521 "JF_JOURNAL_GLOBAL_FILE_ID\n")); 00522 if (jr_file_id == rec_file_id) { 00523 JF_TRACE(("jf_journal_scan_undo: " 00524 "JF_JOURNAL_OP_CODE_COMMIT, " 00525 "jr_file_id == " 00526 "JF_JOURNAL_GLOBAL_FILE_ID, " 00527 "jr_file_id == " 00528 "rec_file_id\n")); 00529 ret_cod = jf_journal_set_all_sync( 00530 journal); 00531 if (JF_RC_OK != ret_cod) 00532 THROW(SET_ALL_SYNC1); 00533 } else { 00534 JF_TRACE(("jf_journal_scan_undo: " 00535 "JF_JOURNAL_OP_CODE_COMMIT, " 00536 "jr_file_id == " 00537 "JF_JOURNAL_GLOBAL_FILE_ID, " 00538 "jr_file_id != " 00539 "rec_file_id\n")); 00540 rec_file = jf_journal_file_tab_get_jfile( 00541 &(journal->file_table), 00542 rec_file_id); 00543 ret_cod = jf_journal_file_set_status( 00544 rec_file, 00545 jf_journal_file_get_status( 00546 rec_file) | 00547 JF_JOURNAL_FILE_ST_SYNC); 00548 if (JF_RC_OK != ret_cod) 00549 THROW(FILE_SET_STATUS0); 00550 } /* if (jr_file_id == rec_file_id) */ 00551 } else { /* jr_file_id == JF_JOURNAL_GLOBAL_FILE_ID */ 00552 JF_TRACE(("jf_journal_scan_undo: " 00553 "JF_JOURNAL_OP_CODE_COMMIT, " 00554 "jr_file_id != " 00555 "JF_JOURNAL_GLOBAL_FILE_ID\n")); 00556 if (jr_file_id == rec_file_id || 00557 rec_file_id == JF_JOURNAL_GLOBAL_FILE_ID) { 00558 JF_TRACE(("jf_journal_scan_undo: " 00559 "JF_JOURNAL_OP_CODE_COMMIT, " 00560 "jr_file_id != " 00561 "JF_JOURNAL_GLOBAL_FILE_ID, " 00562 "jr_file_id == " 00563 "rec_file_id\n")); 00564 JF_TRACE(("jf_journal_scan_undo: " 00565 "jr_file_id = " 00566 JF_WORD_T_FORMAT 00567 ", status = " 00568 JF_WORD_T_FORMAT "\n", 00569 jr_file_id, 00570 jf_journal_file_get_status( 00571 jfile))); 00572 ret_cod = jf_journal_file_set_status( 00573 jfile, 00574 jf_journal_file_get_status( 00575 jfile) | 00576 JF_JOURNAL_FILE_ST_SYNC); 00577 if (JF_RC_OK != ret_cod) 00578 THROW(FILE_SET_STATUS1); 00579 JF_TRACE(("jf_journal_scan_undo: " 00580 "jr_file_id = " 00581 JF_WORD_T_FORMAT 00582 ", status = " 00583 JF_WORD_T_FORMAT "\n", 00584 jr_file_id, 00585 jf_journal_file_get_status( 00586 jfile))); 00587 /* check if scan should be interr. */ 00588 if ((jr_file_id == rec_file_id && 00589 jf_journal_file_get_status( 00590 jfile) & 00591 JF_JOURNAL_FILE_ST_SYNC)) 00592 THROW(END_OF_FILE2); 00593 } /* if (jr_file_id == rec_file_id || ... */ 00594 } /* if (jr_file_id == JF_JOURNAL_GLOBAL_FILE_ID) */ 00595 if (jf_journal_is_sync(journal, rec_file_id)) 00596 THROW(END_OF_FILE3); 00597 /* move journal backward */ 00598 jrn_stream = jf_journal_get_stream(journal); 00599 if (0 != fseeko(jrn_stream, 00600 -((jf_offset_t)sizeof(ctrl_code)), 00601 SEEK_CUR)) 00602 THROW(FSEEK_ERROR1); 00603 break; 00604 case JF_JOURNAL_OP_CODE_ROLLBACK: 00605 JF_TRACE(("jf_journal_scan_undo: " 00606 "JF_JOURNAL_OP_CODE_ROLLBACK\n")); 00607 if (jr_file_id == JF_JOURNAL_GLOBAL_FILE_ID) { 00608 JF_TRACE(("jf_journal_scan_undo: " 00609 "JF_JOURNAL_OP_CODE_ROLLBACK, " 00610 "jr_file_id == " 00611 "JF_JOURNAL_GLOBAL_FILE_ID\n")); 00612 if (jr_file_id == rec_file_id) { 00613 JF_TRACE(("jf_journal_scan_undo: " 00614 "JF_JOURNAL_OP_CODE_ROLLBACK" 00615 ", jr_file_id == " 00616 "JF_JOURNAL_GLOBAL_FILE_ID " 00617 "jr_file_id == " 00618 "rec_file_id\n")); 00619 ret_cod = jf_journal_set_all_sync( 00620 journal); 00621 if (JF_RC_OK != ret_cod) 00622 THROW(SET_ALL_SYNC2); 00623 } else { 00624 JF_TRACE(("jf_journal_scan_undo: " 00625 "JF_JOURNAL_OP_CODE_ROLLBACK" 00626 ", jr_file_id == " 00627 "JF_JOURNAL_GLOBAL_FILE_ID " 00628 "jr_file_id != " 00629 "rec_file_id\n")); 00630 JF_TRACE(("jf_journal_scan_undo: " 00631 "jr_file_id = " 00632 JF_WORD_T_FORMAT 00633 ", status = " 00634 JF_WORD_T_FORMAT 00635 "\n", jr_file_id, 00636 jf_journal_file_get_status( 00637 jfile))); 00638 ret_cod = jf_journal_file_set_status( 00639 jfile, 00640 jf_journal_file_get_status( 00641 jfile) | 00642 JF_JOURNAL_FILE_ST_SYNC); 00643 if (JF_RC_OK != ret_cod) 00644 THROW(FILE_SET_STATUS2); 00645 JF_TRACE(("jf_journal_scan_undo: " 00646 "jr_file_id = " 00647 JF_WORD_T_FORMAT 00648 ", status = " 00649 JF_WORD_T_FORMAT "\n", 00650 jr_file_id, 00651 jf_journal_file_get_status( 00652 jfile))); 00653 } /* if (jr_file_id == rec_file_id) */ 00654 } else { 00655 JF_TRACE(("jf_journal_scan_undo: " 00656 "JF_JOURNAL_OP_CODE_ROLLBACK, " 00657 "jr_file_id != " 00658 "JF_JOURNAL_GLOBAL_FILE_ID\n")); 00659 if (jr_file_id == rec_file_id) { 00660 JF_TRACE(("jf_journal_scan_undo: " 00661 "JF_JOURNAL_OP_CODE_ROLLBACK" 00662 ", jr_file_id != " 00663 "JF_JOURNAL_GLOBAL_FILE_ID" 00664 "jr_file_id == " 00665 "rec_file_id\n")); 00666 JF_TRACE(("jf_journal_scan_undo: " 00667 "jr_file_id = " 00668 JF_WORD_T_FORMAT 00669 ", status = " 00670 JF_WORD_T_FORMAT 00671 "\n", jr_file_id, 00672 jf_journal_file_get_status( 00673 jfile))); 00674 ret_cod = jf_journal_file_set_status( 00675 jfile, 00676 jf_journal_file_get_status( 00677 jfile) | 00678 JF_JOURNAL_FILE_ST_SYNC); 00679 if (JF_RC_OK != ret_cod) 00680 THROW(FILE_SET_STATUS2); 00681 JF_TRACE(("jf_journal_scan_undo: " 00682 "jr_file_id = " 00683 JF_WORD_T_FORMAT 00684 ", status = " 00685 JF_WORD_T_FORMAT "\n", 00686 jr_file_id, 00687 jf_journal_file_get_status( 00688 jfile))); 00689 } /* if (jr_file_id == rec_file_id) */ 00690 /* check if scan should be interrupted */ 00691 if ((jr_file_id == rec_file_id && 00692 jf_journal_file_get_status(jfile) & 00693 JF_JOURNAL_FILE_ST_SYNC)) 00694 THROW(END_OF_FILE4); 00695 } /* if (jr_file_id == JF_JOURNAL_GLOBAL_FILE_ID) && */ 00696 if (jf_journal_is_sync(journal, rec_file_id)) 00697 THROW(END_OF_FILE5); 00698 /* move journal backward */ 00699 jrn_stream = jf_journal_get_stream(journal); 00700 if (0 != fseeko(jrn_stream, 00701 -((jf_offset_t)sizeof(ctrl_code)), 00702 SEEK_CUR)) 00703 THROW(FSEEK_ERROR2); 00704 break; 00705 default: /* apply changes */ 00706 if ((rec_file_id != JF_JOURNAL_GLOBAL_FILE_ID && 00707 jr_file_id != rec_file_id)) /* skip this record */ 00708 THROW(SKIP_RECORD); 00709 ret_cod = jf_journal_remove_changes(journal, jr); 00710 if (JF_RC_OK != ret_cod) 00711 THROW(APPLY_CHANGES); 00712 break; 00713 } /* switch (ctrl_code) */ 00714 00715 THROW(NONE); 00716 } CATCH { 00717 switch (excp) { 00718 case END_OF_FILE1: 00719 case END_OF_FILE2: 00720 case END_OF_FILE3: 00721 case END_OF_FILE4: 00722 case END_OF_FILE5: 00723 ret_cod = JF_RC_EOF; 00724 break; 00725 case FETCH_RECORD: 00726 case SET_ALL_SYNC1: 00727 case SET_ALL_SYNC2: 00728 case FILE_SET_ALL_IN_CACHE: 00729 case FILE_SET_STATUS0: 00730 case FILE_SET_STATUS1: 00731 case FILE_SET_STATUS2: 00732 case APPLY_CHANGES: 00733 break; 00734 case INVALID_STATUS: 00735 ret_cod = JF_RC_INTERNAL_ERROR; 00736 break; 00737 case FSEEK_ERROR1: 00738 case FSEEK_ERROR2: 00739 ret_cod = JF_RC_FSEEK_ERROR; 00740 break; 00741 case SKIP_RECORD: 00742 case NONE: 00743 ret_cod = JF_RC_OK; 00744 break; 00745 default: 00746 ret_cod = JF_RC_INTERNAL_ERROR; 00747 } /* switch (excp) */ 00748 } /* TRY-CATCH */ 00749 JF_TRACE(("jf_journal_scan_undo/excp=%d/ret_cod=%d/errno=%d\n", 00750 excp, ret_cod, errno)); 00751 return ret_cod; 00752 } 00753 00754 00755 00756 int jf_journal_reopen_files(jf_journal_t *journal) 00757 { 00758 enum Exception { FILE_OPEN_STREAM 00759 , NONE } excp; 00760 int ret_cod = JF_RC_INTERNAL_ERROR; 00761 00762 JF_TRACE(("jf_journal_reopen_files\n")); 00763 TRY { 00764 jf_word_t nof = jf_journal_file_tab_get_number_of_files( 00765 &(journal->file_table)); 00766 jf_word_t i; 00767 00768 for (i = 0; i < nof; ++i) { 00769 const jf_journal_file_t *jfile = 00770 jf_journal_file_tab_get_jfile( 00771 &(journal->file_table), i); 00772 FILE *stream = jf_journal_file_get_stream(jfile); 00773 00774 if (stream == NULL && 00775 jf_journal_file_get_status(jfile) & 00776 JF_JOURNAL_FILE_ST_OPEN) { 00777 jf_file_t jf; 00778 /* try to open an existing file... */ 00779 ret_cod = jf_file_open( 00780 &jf, journal, 00781 jf_journal_file_get_path(jfile), 00782 "r+", NULL); 00783 if (JF_RC_OK != ret_cod) 00784 THROW(FILE_OPEN_STREAM); 00785 } /* if (stream == NULL) */ 00786 } /* for (i = 0; i < nof; ++i) */ 00787 00788 THROW(NONE); 00789 } CATCH { 00790 switch (excp) { 00791 case FILE_OPEN_STREAM: 00792 break; 00793 case NONE: 00794 ret_cod = JF_RC_OK; 00795 break; 00796 default: 00797 ret_cod = JF_RC_INTERNAL_ERROR; 00798 } /* switch (excp) */ 00799 } /* TRY-CATCH */ 00800 JF_TRACE(("jf_journal_reopen_files/excp=%d/ret_cod=%d/" 00801 "errno=%d\n", excp, ret_cod, errno)); 00802 return ret_cod; 00803 } 00804 00805 00806 00807 int jf_journal_fetch_record(const jf_journal_t *journal, 00808 struct jf_journal_record_s *jr, int forward) 00809 { 00810 enum Exception { EOF_REACHED1 00811 , FSEEK_ERROR1 00812 , FTELL_ERROR1 00813 , EOF_REACHED2 00814 , INVALID_STREAM_POSITION 00815 , EOF_REACHED3 00816 , FREAD_ERROR1 00817 , INVALID_REDO_UNDO_FLAG1 00818 , INVALID_OPERATOR_CODE1 00819 , REALLOC_ERROR1 00820 , REALLOC_ERROR2 00821 , FSEEK_ERROR2 00822 , FREAD_ERROR2 00823 , REALLOC_ERROR3 00824 , REALLOC_ERROR4 00825 , FSEEK_ERROR3 00826 , FREAD_ERROR3 00827 , FSEEK_ERROR4 00828 , FSEEK_ERROR5 00829 , FSEEK_ERROR6 00830 , FSEEK_ERROR7 00831 , FSEEK_ERROR8 00832 , FREAD_ERROR4 00833 , FREAD_ERROR5 00834 , FREAD_ERROR6 00835 , INVALID_REDO_UNDO_FLAG2 00836 , INVALID_OPERATOR_CODE2 00837 , NONE } excp; 00838 int ret_cod = JF_RC_INTERNAL_ERROR; 00839 00840 JF_TRACE(("jf_journal_fetch_record\n")); 00841 TRY { 00842 byte_t *tmp_data = NULL; 00843 jf_word_t ctrl_code, op, size; 00844 FILE *jrn_stream = jf_journal_get_stream(journal); 00845 00846 if (forward) { 00847 if (feof(jrn_stream)) 00848 THROW(EOF_REACHED1); 00849 } else { 00850 jf_offset_t curr_pos; 00851 /* go one word back */ 00852 if (0 != fseeko(jrn_stream, 00853 -((jf_offset_t)sizeof(ctrl_code)), 00854 SEEK_CUR)) 00855 THROW(FSEEK_ERROR1); 00856 if (0 > (curr_pos = ftello(jrn_stream))) 00857 THROW(FTELL_ERROR1); 00858 if (curr_pos <= journal->journal_recs) { 00859 THROW(EOF_REACHED2); 00860 } else if (curr_pos == journal->journal_recs) 00861 THROW(INVALID_STREAM_POSITION); 00862 } /* if (forward) */ 00863 00864 JF_TRACE(("jf_journal_fetch_record: curr_pos = " 00865 JF_OFFSET_T_FORMAT "\n", ftello(jrn_stream))); 00866 00867 /* reset previous codes */ 00868 jr->redo_code = jr->undo_code = JF_JOURNAL_OP_CODE_NULL; 00869 00870 /* read ctrl_code */ 00871 if (1 != fread(&ctrl_code, sizeof(ctrl_code), 1, jrn_stream)) { 00872 if (feof(jrn_stream)) { 00873 THROW(EOF_REACHED3); 00874 } else { 00875 THROW(FREAD_ERROR1); 00876 } /* if (feof(jrn_stream) */ 00877 } /* if (1 != fread(&ctrl_code, ... */ 00878 00879 JF_TRACE(("jf_journal_fetch_record: code = %X (%s)\n", 00880 ctrl_code, jf_journal_describe_code(ctrl_code))); 00881 00882 if (forward) 00883 jr->redo_code = ctrl_code; 00884 else 00885 jr->undo_code = ctrl_code; 00886 00887 /* break code */ 00888 op = ctrl_code & JF_JOURNAL_OP_MASK; 00889 00890 size = (ctrl_code & journal->size_mask) >> 00891 journal->size_mask_shift; 00892 00893 /* keep only operation in ctrl_code */ 00894 ctrl_code &= JF_JOURNAL_OP_CODE_MASK; 00895 /* check operation code */ 00896 switch (ctrl_code) { 00897 case JF_JOURNAL_OP_CODE_APPEND: 00898 case JF_JOURNAL_OP_CODE_UPDATE: 00899 /* check redo/undo flag */ 00900 if (((op & JF_JOURNAL_OP_DO) && !forward) || 00901 (!(op & JF_JOURNAL_OP_DO) && forward)) 00902 THROW(INVALID_REDO_UNDO_FLAG1); 00903 break; 00904 case JF_JOURNAL_OP_CODE_SYNC: 00905 THROW(NONE); 00906 default: 00907 THROW(INVALID_OPERATOR_CODE1); 00908 } /* switch (ctrl_code) */ 00909 00910 /* realloc necessary ? */ 00911 if (!forward && ctrl_code == JF_JOURNAL_OP_CODE_UPDATE) { 00912 /* only "UPDATE" op has a UNDO data segment */ 00913 if (size > jr->undo_data_alloc) { 00914 if (NULL == (tmp_data = realloc(jr->undo_data, 00915 size))) 00916 THROW(REALLOC_ERROR1); 00917 jr->undo_data = tmp_data; 00918 jr->undo_data_alloc = size; 00919 } /* if (size > jr->undo_data_alloc) */ 00920 } else { 00921 if (size > jr->redo_data_alloc) { 00922 if (NULL == (tmp_data = realloc(jr->redo_data, 00923 size))) 00924 THROW(REALLOC_ERROR2); 00925 jr->redo_data = tmp_data; 00926 jr->redo_data_alloc = size; 00927 } /* if (size > jr->redo_data_alloc) */ 00928 } /* if (!forward) && ctrl_code == ... */ 00929 00930 /* go back */ 00931 if (!forward && 00932 0 != fseeko( 00933 jrn_stream, 00934 -((jf_offset_t)(sizeof(ctrl_code)) + 00935 (jf_offset_t)size), SEEK_CUR)) 00936 THROW(FSEEK_ERROR2); 00937 00938 /* read file offset (forward scan) */ 00939 if (forward && 00940 (ctrl_code == JF_JOURNAL_OP_CODE_UPDATE || 00941 ctrl_code == JF_JOURNAL_OP_CODE_APPEND)) { 00942 if (1 != fread(&(jr->offset), sizeof(jr->offset), 1, 00943 jrn_stream)) 00944 THROW(FREAD_ERROR2); 00945 } /* if (forward &&... */ 00946 00947 /* read data */ 00948 tmp_data = (!forward && ctrl_code == 00949 JF_JOURNAL_OP_CODE_UPDATE) ? 00950 jr->undo_data : jr->redo_data; 00951 if (1 != fread(tmp_data, size, 1, jrn_stream)) 00952 THROW(FREAD_ERROR3); 00953 00954 /* only UPDATE has a second data segment */ 00955 if (ctrl_code == JF_JOURNAL_OP_CODE_UPDATE) { 00956 /* realloc necessary ? */ 00957 if (forward) { 00958 if (size > jr->undo_data_alloc) { 00959 if (NULL == (tmp_data = realloc( 00960 jr->undo_data, 00961 size))) 00962 THROW(REALLOC_ERROR3); 00963 jr->undo_data = tmp_data; 00964 jr->undo_data_alloc = size; 00965 } /* if (size > jr->undo_data_alloc) */ 00966 } else { 00967 if (size > jr->redo_data_alloc) { 00968 if (NULL == (tmp_data = realloc( 00969 jr->redo_data, 00970 size))) 00971 THROW(REALLOC_ERROR4); 00972 jr->redo_data = tmp_data; 00973 jr->redo_data_alloc = size; 00974 } /* if (size > jr->redo_data_alloc) */ 00975 } /* if (!forward) && ctrl_code == ... */ 00976 00977 /* go back */ 00978 if (!forward && 00979 0 != fseeko( 00980 jrn_stream, -((jf_offset_t)(size * 2)), 00981 SEEK_CUR)) 00982 THROW(FSEEK_ERROR3); 00983 00984 /* read data */ 00985 tmp_data = forward ? jr->undo_data : jr->redo_data; 00986 if (1 != fread(tmp_data, size, 1, jrn_stream)) 00987 THROW(FREAD_ERROR4); 00988 } /* if (ctrl_code == JF_JOURNAL_OP_CODE_UPDATE) */ 00989 00990 /* go back */ 00991 if (!forward && 00992 0 != fseeko( 00993 jrn_stream, -((jf_offset_t)size), SEEK_CUR)) 00994 THROW(FSEEK_ERROR4); 00995 00996 /* read file offset (backward scan) */ 00997 if (!forward && 00998 (ctrl_code == JF_JOURNAL_OP_CODE_UPDATE || 00999 ctrl_code == JF_JOURNAL_OP_CODE_APPEND)) { 01000 if (0 != fseeko(jrn_stream, 01001 -((jf_offset_t)sizeof(jf_offset_t)), 01002 SEEK_CUR)) 01003 THROW(FSEEK_ERROR5); 01004 if (1 != fread(&(jr->offset), sizeof(jr->offset), 1, 01005 jrn_stream)) 01006 THROW(FREAD_ERROR5); 01007 if (0 != fseeko(jrn_stream, 01008 -((jf_offset_t)sizeof(jf_offset_t)), 01009 SEEK_CUR)) 01010 THROW(FSEEK_ERROR6); 01011 } /* if (forward &&... */ 01012 01013 /* go back */ 01014 if (!forward && 01015 0 != fseeko( 01016 jrn_stream, -((jf_offset_t)sizeof(ctrl_code)), 01017 SEEK_CUR)) 01018 THROW(FSEEK_ERROR7); 01019 01020 /* read ctrl_code */ 01021 if (1 != fread(&ctrl_code, sizeof(ctrl_code), 1, jrn_stream)) 01022 THROW(FREAD_ERROR6); 01023 if (forward) 01024 jr->undo_code = ctrl_code; 01025 else 01026 jr->redo_code = ctrl_code; 01027 01028 /* go back */ 01029 if (!forward && 01030 0 != fseeko( 01031 jrn_stream, -((jf_offset_t)sizeof(ctrl_code)), 01032 SEEK_CUR)) 01033 THROW(FSEEK_ERROR8); 01034 01035 /* break code */ 01036 op = ctrl_code & JF_JOURNAL_OP_MASK; 01037 size = (ctrl_code & journal->size_mask) >> 01038 journal->size_mask_shift; 01039 01040 /* check redo/undo flag */ 01041 if (((op & JF_JOURNAL_OP_DO) && forward) || 01042 (!(op & JF_JOURNAL_OP_DO) && !forward)) 01043 THROW(INVALID_REDO_UNDO_FLAG2); 01044 01045 /* check operation: it must be the same in undo/redo */ 01046 if ((jr->undo_code & JF_JOURNAL_OP_CODE_MASK) != 01047 (jr->redo_code & JF_JOURNAL_OP_CODE_MASK)) 01048 THROW(INVALID_OPERATOR_CODE2); 01049 01050 JF_TRACE(("jf_journal_fetch_record: " 01051 "undo_code = %X, redo_code = %X, " 01052 "offset = " JF_OFFSET_T_FORMAT ", " 01053 "undo_data_alloc = " JF_WORD_T_FORMAT ", " 01054 "redo_data_alloc = " JF_WORD_T_FORMAT "\n", 01055 jr->undo_code, jr->redo_code, jr->offset, 01056 jr->undo_data_alloc, jr->redo_data_alloc)); 01057 01058 THROW(NONE); 01059 } CATCH { 01060 switch (excp) { 01061 case EOF_REACHED1: 01062 case EOF_REACHED2: 01063 case EOF_REACHED3: 01064 ret_cod = JF_RC_EOF; 01065 break; 01066 case FSEEK_ERROR1: 01067 case FSEEK_ERROR2: 01068 case FSEEK_ERROR3: 01069 case FSEEK_ERROR4: 01070 case FSEEK_ERROR5: 01071 case FSEEK_ERROR6: 01072 case FSEEK_ERROR7: 01073 case FSEEK_ERROR8: 01074 ret_cod = JF_RC_FSEEK_ERROR; 01075 break; 01076 case FTELL_ERROR1: 01077 ret_cod = JF_RC_FTELL_ERROR; 01078 break; 01079 case FREAD_ERROR1: 01080 case FREAD_ERROR2: 01081 case FREAD_ERROR3: 01082 case FREAD_ERROR4: 01083 case FREAD_ERROR5: 01084 case FREAD_ERROR6: 01085 ret_cod = JF_RC_FREAD_ERROR; 01086 break; 01087 case REALLOC_ERROR1: 01088 case REALLOC_ERROR2: 01089 case REALLOC_ERROR3: 01090 case REALLOC_ERROR4: 01091 ret_cod = JF_RC_REALLOC_ERROR; 01092 break; 01093 case INVALID_REDO_UNDO_FLAG1: 01094 case INVALID_REDO_UNDO_FLAG2: 01095 case INVALID_OPERATOR_CODE1: 01096 case INVALID_OPERATOR_CODE2: 01097 ret_cod = JF_RC_INVALID_CTRL_CODE; 01098 break; 01099 case INVALID_STREAM_POSITION: 01100 ret_cod = JF_RC_INVALID_STREAM_POSITION; 01101 break; 01102 case NONE: 01103 ret_cod = JF_RC_OK; 01104 break; 01105 default: 01106 ret_cod = JF_RC_INTERNAL_ERROR; 01107 } /* switch (excp) */ 01108 } /* TRY-CATCH */ 01109 JF_TRACE(("jf_journal_fetch_record/excp=%d/ret_cod=%d/" 01110 "errno=%d\n", excp, ret_cod, errno)); 01111 return ret_cod; 01112 } 01113 01114 01115 01116 int jf_journal_apply_changes(const jf_journal_t *journal, 01117 const struct jf_journal_record_s *jr) 01118 { 01119 enum Exception { INVALID_OPER 01120 , INVALID_FILE_ID 01121 , INVALID_STREAM 01122 , FSEEK_ERROR 01123 , FWRITE_ERROR 01124 , SET_LAST_UC_SIZE 01125 , NONE } excp; 01126 int ret_cod = JF_RC_INTERNAL_ERROR; 01127 01128 JF_TRACE(("jf_journal_apply_changes\n")); 01129 TRY { 01130 jf_word_t oper = jr->redo_code & JF_JOURNAL_OP_CODE_MASK; 01131 jf_journal_file_t *jfile; 01132 FILE *stream; 01133 jf_word_t file_id = (jr->redo_code & journal->file_id_mask) >> 01134 journal->file_id_mask_shift; 01135 jf_word_t nof = jf_journal_file_tab_get_number_of_files( 01136 &(journal->file_table)); 01137 01138 if (oper != JF_JOURNAL_OP_CODE_APPEND && 01139 oper != JF_JOURNAL_OP_CODE_UPDATE) 01140 THROW(INVALID_OPER); 01141 01142 /* check file_id */ 01143 if (file_id == JF_JOURNAL_JOURNAL_FILE_ID || file_id >= nof) 01144 THROW(INVALID_FILE_ID); 01145 01146 /* retrieve journaled file stream */ 01147 jfile = jf_journal_file_tab_get_jfile( 01148 &(journal->file_table), file_id); 01149 stream = jf_journal_file_get_stream(jfile); 01150 01151 /* process only files was opened at syncpoint time */ 01152 if (jf_journal_file_get_status(jfile) & 01153 JF_JOURNAL_FILE_ST_OPEN) { 01154 jf_word_t size = (jr->redo_code & 01155 journal->size_mask) >> 01156 journal->size_mask_shift; 01157 jf_offset_t offset = jr->offset + (jf_offset_t)size; 01158 if (stream == NULL) 01159 THROW(INVALID_STREAM); 01160 if (0 != fseeko(stream, jr->offset, SEEK_SET)) 01161 THROW(FSEEK_ERROR); 01162 if (1 != fwrite(jr->redo_data, size, 1, stream)) 01163 THROW(FWRITE_ERROR); 01164 if (offset > jf_journal_file_get_last_uc_size(jfile)) { 01165 ret_cod = jf_journal_file_set_last_uc_size( 01166 jfile, offset); 01167 if (JF_RC_OK != ret_cod) 01168 THROW(SET_LAST_UC_SIZE); 01169 } /* if (offset > jf_journal_file_get_last_uc_size */ 01170 } /* if (jf_journal_file_get_status... */ 01171 01172 THROW(NONE); 01173 } CATCH { 01174 switch (excp) { 01175 case INVALID_OPER: 01176 case INVALID_FILE_ID: 01177 ret_cod = JF_RC_INVALID_CTRL_CODE; 01178 break; 01179 case INVALID_STREAM: 01180 ret_cod = JF_RC_INVALID_STATUS; 01181 break; 01182 case FSEEK_ERROR: 01183 ret_cod = JF_RC_FSEEK_ERROR; 01184 break; 01185 case FWRITE_ERROR: 01186 ret_cod = JF_RC_FWRITE_ERROR; 01187 break; 01188 case SET_LAST_UC_SIZE: 01189 break; 01190 case NONE: 01191 ret_cod = JF_RC_OK; 01192 break; 01193 default: 01194 ret_cod = JF_RC_INTERNAL_ERROR; 01195 } /* switch (excp) */ 01196 } /* TRY-CATCH */ 01197 JF_TRACE(("jf_journal_apply_changes/excp=%d/ret_cod=%d/" 01198 "errno=%d\n", excp, ret_cod, errno)); 01199 return ret_cod; 01200 } 01201 01202 01203 01204 int jf_journal_remove_changes(const jf_journal_t *journal, 01205 const struct jf_journal_record_s *jr) 01206 { 01207 enum Exception { INVALID_OPER 01208 , INVALID_FILE_ID 01209 , INVALID_STREAM 01210 , FSEEK_ERROR 01211 , FWRITE_ERROR 01212 , NONE } excp; 01213 int ret_cod = JF_RC_INTERNAL_ERROR; 01214 01215 JF_TRACE(("jf_journal_remove_changes\n")); 01216 TRY { 01217 jf_word_t oper = jr->undo_code & JF_JOURNAL_OP_CODE_MASK; 01218 const jf_journal_file_t *jfile; 01219 FILE *stream; 01220 jf_word_t file_id = (jr->undo_code & journal->file_id_mask) >> 01221 journal->file_id_mask_shift; 01222 jf_word_t nof = jf_journal_file_tab_get_number_of_files( 01223 &(journal->file_table)); 01224 01225 if (oper != JF_JOURNAL_OP_CODE_APPEND && 01226 oper != JF_JOURNAL_OP_CODE_UPDATE) 01227 THROW(INVALID_OPER); 01228 01229 /* check file_id */ 01230 if (file_id == JF_JOURNAL_JOURNAL_FILE_ID || file_id >= nof) 01231 THROW(INVALID_FILE_ID); 01232 01233 /* retrieve journaled file stream */ 01234 jfile = jf_journal_file_tab_get_jfile( 01235 &(journal->file_table), file_id); 01236 stream = jf_journal_file_get_stream(jfile); 01237 01238 JF_TRACE(("jf_journal_remove_changes: file_id = " 01239 JF_WORD_T_FORMAT ", file_status = "JF_WORD_T_FORMAT 01240 "\n", file_id, jf_journal_file_get_status(jfile))); 01241 01242 /* process only files were opened at syncpoint time */ 01243 if ((jf_journal_file_get_status(jfile) & 01244 JF_JOURNAL_FILE_ST_OPEN) && 01245 !(jf_journal_file_get_status(jfile) & 01246 JF_JOURNAL_FILE_ST_SYNC)) { 01247 jf_word_t size = 01248 (jr->undo_code & journal->size_mask) >> 01249 journal->size_mask_shift; 01250 JF_TRACE(("jf_journal_remove_changes: file_id " 01251 "= %u, offset = " JF_OFFSET_T_FORMAT ", " 01252 "size = " JF_WORD_T_FORMAT "\n", 01253 file_id, jr->offset, size)); 01254 if (stream == NULL) 01255 THROW(INVALID_STREAM); 01256 if (0 != fseeko(stream, jr->offset, SEEK_SET)) 01257 THROW(FSEEK_ERROR); 01258 if (oper == JF_JOURNAL_OP_CODE_UPDATE && 01259 1 != fwrite(jr->undo_data, size, 1, stream)) 01260 THROW(FWRITE_ERROR); 01261 } /* if (jf_journal_file_get_status... */ 01262 JF_CRASH_SIMUL((JF_CRASH_SIMUL_F_REMOVE_CHANGES_1)); 01263 01264 THROW(NONE); 01265 } CATCH { 01266 switch (excp) { 01267 case INVALID_OPER: 01268 case INVALID_FILE_ID: 01269 ret_cod = JF_RC_INVALID_CTRL_CODE; 01270 break; 01271 case INVALID_STREAM: 01272 ret_cod = JF_RC_INVALID_STATUS; 01273 break; 01274 case FSEEK_ERROR: 01275 ret_cod = JF_RC_FSEEK_ERROR; 01276 break; 01277 case FWRITE_ERROR: 01278 ret_cod = JF_RC_FWRITE_ERROR; 01279 break; 01280 case NONE: 01281 ret_cod = JF_RC_OK; 01282 break; 01283 default: 01284 ret_cod = JF_RC_INTERNAL_ERROR; 01285 } /* switch (excp) */ 01286 } /* TRY-CATCH */ 01287 JF_TRACE(("jf_journal_remove_changes/excp=%d/ret_cod=%d/" 01288 "errno=%d\n", excp, ret_cod, errno)); 01289 return ret_cod; 01290 } 01291 01292 01293 01294 const char *jf_journal_describe_code(const jf_word_t ctrl_code) 01295 { 01296 switch (ctrl_code & JF_JOURNAL_OP_MASK) { 01297 case JF_JOURNAL_OP_CODE_APPEND | JF_JOURNAL_OP_DO: 01298 return "REDO APPEND"; 01299 case JF_JOURNAL_OP_CODE_APPEND: 01300 return "UNDO APPEND"; 01301 case JF_JOURNAL_OP_CODE_UPDATE | JF_JOURNAL_OP_DO: 01302 return "REDO UPDATE"; 01303 case JF_JOURNAL_OP_CODE_UPDATE: 01304 return "UNDO UPDATE"; 01305 case JF_JOURNAL_OP_CODE_SYNC | JF_JOURNAL_OP_DO: 01306 return "COMMIT"; 01307 case JF_JOURNAL_OP_CODE_SYNC: 01308 return "ROLLBACK"; 01309 default: 01310 return "UNKNOWN CODE"; 01311 } /* switch (ctrl_code & JF_JOURNAL_OP_MASK) */ 01312 } 01313 01314 01315 01316 int jf_journal_trace_record(const jf_journal_t *journal, 01317 const struct jf_journal_record_s *jr, 01318 jf_offset_t record_offset, FILE *out_stream, 01319 uint32_t flags) 01320 { 01321 enum Exception { INVALID_OPERATOR_CODE 01322 , NONE } excp; 01323 int ret_cod = JF_RC_INTERNAL_ERROR; 01324 01325 JF_TRACE(("jf_journal_trace_record\n")); 01326 TRY { 01327 jf_word_t size, file_id, op; 01328 01329 op = jr->redo_code & JF_JOURNAL_OP_MASK; 01330 file_id = (jr->redo_code & journal->file_id_mask) >> 01331 journal->file_id_mask_shift; 01332 size = (jr->redo_code & journal->size_mask) >> 01333 journal->size_mask_shift; 01334 01335 switch (op & JF_JOURNAL_OP_CODE_MASK) { 01336 case JF_JOURNAL_OP_CODE_APPEND: 01337 fprintf(out_stream, " <append " 01338 "jrn_rec_off='" JF_OFFSET_T_FORMAT "' " 01339 "file_id='" JF_WORD_T_FORMAT "' " 01340 "size='" JF_WORD_T_FORMAT "' " 01341 "offset='" JF_OFFSET_T_FORMAT "'>\n", 01342 record_offset, file_id, size, jr->offset); 01343 if (flags & JF_JOURNAL_ANALYZE_TRACE_HEX_DATA) { 01344 fprintf(out_stream, " <data type='redo' " 01345 "format='hex'>"); 01346 jf_trace_hex_data(jr->redo_data, size, 01347 out_stream); 01348 fprintf(out_stream, "</data>\n"); 01349 } /* if (flags & JF_JOURNAL_ANALYZE_TRACE_HEX_DATA) */ 01350 if (flags & JF_JOURNAL_ANALYZE_TRACE_TEXT_DATA) { 01351 fprintf(out_stream, 01352 " <data type='redo' " 01353 "format='text'>"); 01354 jf_trace_text_data(jr->redo_data, size, 01355 out_stream); 01356 fprintf(out_stream, "</data>\n"); 01357 } /* if (flags & JF_JOURNAL_ANALYZE_TRACE_TEXT_DATA) */ 01358 fprintf(out_stream, " </append>\n"); 01359 break; 01360 case JF_JOURNAL_OP_CODE_UPDATE: 01361 fprintf(out_stream, " <update " 01362 "jrn_rec_off='" JF_OFFSET_T_FORMAT "' " 01363 "file_id='" JF_WORD_T_FORMAT "' " 01364 "size='" JF_WORD_T_FORMAT "' " 01365 "offset='" JF_OFFSET_T_FORMAT "'>\n", 01366 record_offset, file_id, size, jr->offset); 01367 if (flags & JF_JOURNAL_ANALYZE_TRACE_HEX_DATA) { 01368 fprintf(out_stream, " <data type='redo' " 01369 "format='hex'>"); 01370 jf_trace_hex_data(jr->redo_data, size, 01371 out_stream); 01372 fprintf(out_stream, "</data>\n"); 01373 } /* if (flags & JF_JOURNAL_ANALYZE_TRACE_HEX_DATA) */ 01374 if (flags & JF_JOURNAL_ANALYZE_TRACE_TEXT_DATA) { 01375 fprintf(out_stream, 01376 " <data type='redo' " 01377 "format='text'>"); 01378 jf_trace_text_data(jr->redo_data, size, 01379 out_stream); 01380 fprintf(out_stream, "</data>\n"); 01381 } /* if (flags & JF_JOURNAL_ANALYZE_TRACE_TEXT_DATA) */ 01382 if (flags & JF_JOURNAL_ANALYZE_TRACE_HEX_DATA) { 01383 fprintf(out_stream, " <data type='undo' " 01384 "format='hex'>"); 01385 jf_trace_hex_data(jr->undo_data, size, 01386 out_stream); 01387 fprintf(out_stream, "</data>\n"); 01388 } /* if (flags & JF_JOURNAL_ANALYZE_TRACE_HEX_DATA) */ 01389 if (flags & JF_JOURNAL_ANALYZE_TRACE_TEXT_DATA) { 01390 fprintf(out_stream, 01391 " <data type='undo' " 01392 "format='text'>"); 01393 jf_trace_text_data(jr->undo_data, size, 01394 out_stream); 01395 fprintf(out_stream, "</data>\n"); 01396 } /* if (flags & JF_JOURNAL_ANALYZE_TRACE_TEXT_DATA) */ 01397 fprintf(out_stream, " </update>\n"); 01398 break; 01399 case JF_JOURNAL_OP_CODE_SYNC: 01400 fprintf(out_stream, 01401 " <%s " 01402 "jrn_rec_off='" JF_OFFSET_T_FORMAT "' " 01403 "file_id='" JF_WORD_T_FORMAT "'/>\n", 01404 (op & JF_JOURNAL_OP_DO) ? 01405 "commit" : "rollback", record_offset, file_id); 01406 break; 01407 default: 01408 THROW(INVALID_OPERATOR_CODE); 01409 } /* switch (op) */ 01410 01411 THROW(NONE); 01412 } CATCH { 01413 switch (excp) { 01414 case INVALID_OPERATOR_CODE: 01415 ret_cod = JF_RC_INVALID_CTRL_CODE; 01416 break; 01417 case NONE: 01418 ret_cod = JF_RC_OK; 01419 break; 01420 default: 01421 ret_cod = JF_RC_INTERNAL_ERROR; 01422 } /* switch (excp) */ 01423 } /* TRY-CATCH */ 01424 JF_TRACE(("jf_journal_trace_record/excp=%d/ret_cod=%d/" 01425 "errno=%d\n", excp, ret_cod, errno)); 01426 return ret_cod; 01427 } 01428

Copyright 2005 © Tiian