/** * Just a performance optimization. Sometimes it makes sense to verify a log * when we are inserting a new entry. We combine this into one operation so * that we don't iterate through the log twice. * * As opposed to the simple insert function, this /does/ check to see if the * object has already been inserted. In the case where the object already * exists and is current, we don't add it again. * * If the verification fails we'll abort * * @param shared The address of the object that we read from. * @param version The version of the object that we read. * * @throws stm::RollBack */ void insertAndVerifyReads(Object* shared, unsigned long version) { assert(shared); for (ReadLog::iterator i = reads.begin(), e = reads.end(); i != e; ++i) { if (!isCurrent(i->shared, i->version)) abort(); if (shared == i->shared) return; } reads.insert(ReadLogEntry(shared, version)); }
ClassAdLog::ClassAdLog(const char *filename,int max_historical_logs_arg) : table(CLASSAD_LOG_HASHTABLE_SIZE, hashFunction) { log_filename_buf = filename; active_transaction = NULL; m_nondurable_level = 0; this->max_historical_logs = max_historical_logs_arg; historical_sequence_number = 1; m_original_log_birthdate = time(NULL); int log_fd = safe_open_wrapper_follow(logFilename(), O_RDWR | O_CREAT | O_LARGEFILE, 0600); if (log_fd < 0) { EXCEPT("failed to open log %s, errno = %d", logFilename(), errno); } log_fp = fdopen(log_fd, "r+"); if (log_fp == NULL) { EXCEPT("failed to fdopen log %s, errno = %d", logFilename(), errno); } // Read all of the log records LogRecord *log_rec; unsigned long count = 0; bool is_clean = true; // was cleanly closed (until we find out otherwise) bool requires_successful_cleaning = false; long long next_log_entry_pos = 0; long long curr_log_entry_pos = 0; while ((log_rec = ReadLogEntry(log_fp, 1+count, InstantiateLogEntry)) != 0) { curr_log_entry_pos = next_log_entry_pos; next_log_entry_pos = ftell(log_fp); count++; switch (log_rec->get_op_type()) { case CondorLogOp_Error: // this is defensive, ought to be caught in InstantiateLogEntry() EXCEPT("ERROR: transaction record %lu was bad (byte offset %lld)\n", count, curr_log_entry_pos); break; case CondorLogOp_BeginTransaction: // this file contains transactions, so it must not // have been cleanly shut down is_clean = false; if (active_transaction) { dprintf(D_ALWAYS, "Warning: Encountered nested transactions in %s, " "log may be bogus...", filename); } else { active_transaction = new Transaction(); } delete log_rec; break; case CondorLogOp_EndTransaction: if (!active_transaction) { dprintf(D_ALWAYS, "Warning: Encountered unmatched end transaction in %s, " "log may be bogus...", filename); } else { active_transaction->Commit(NULL, (void *)&table); // commit in memory only delete active_transaction; active_transaction = NULL; } delete log_rec; break; case CondorLogOp_LogHistoricalSequenceNumber: if(count != 1) { dprintf(D_ALWAYS, "Warning: Encountered historical sequence number after first log entry (entry number = %ld)\n",count); } historical_sequence_number = ((LogHistoricalSequenceNumber *)log_rec)->get_historical_sequence_number(); m_original_log_birthdate = ((LogHistoricalSequenceNumber *)log_rec)->get_timestamp(); delete log_rec; break; default: if (active_transaction) { active_transaction->AppendLog(log_rec); } else { log_rec->Play((void *)&table); delete log_rec; } } } long long final_log_entry_pos = ftell(log_fp); if( next_log_entry_pos != final_log_entry_pos ) { // The log file has a broken line at the end so we _must_ // _not_ write anything more into this log. // (Alternately, we could try to clear out the broken entry // and continue writing into this file, but since we are about to // rotate the log anyway, we may as well just require the rotation // to be successful. In the case where rotation fails, we will // probably soon fail to write to the log file anyway somewhere else.) dprintf(D_ALWAYS,"Detected unterminated log entry in ClassAd Log %s." " Forcing rotation.\n", logFilename()); requires_successful_cleaning = true; } if (active_transaction) { // abort incomplete transaction delete active_transaction; active_transaction = NULL; if( !requires_successful_cleaning ) { // For similar reasons as with broken log entries above, // we need to force rotation. dprintf(D_ALWAYS,"Detected unterminated transaction in ClassAd Log" "%s. Forcing rotation.\n", logFilename()); requires_successful_cleaning = true; } } if(!count) { log_rec = new LogHistoricalSequenceNumber( historical_sequence_number, m_original_log_birthdate ); if (log_rec->Write(log_fp) < 0) { EXCEPT("write to %s failed, errno = %d", logFilename(), errno); } } if( !is_clean || requires_successful_cleaning ) { if( !TruncLog() && requires_successful_cleaning ) { EXCEPT("Failed to rotate ClassAd log %s.\n", logFilename()); } } }
int LogHandler(char cmd, int id_in, varList **commands, int *id_out) { int ret = 0; FILE *post_file = NULL; FILE *pre_file = NULL; char *post_log = NULL; char *pre_log = NULL; int post_log_len = strlen(LOG_PATH) + strlen(LOG_POST_NAME) + strlen(DB_GLOBAL) + 1; int pre_log_len = strlen(LOG_PATH) + strlen(LOG_PRE_NAME) + strlen(DB_GLOBAL) + 1; post_log = (char *)malloc(sizeof(char *) * post_log_len); pre_log = (char *)malloc(sizeof(char *) * pre_log_len); strncpy(post_log, LOG_PATH, post_log_len); strncat(post_log, DB_GLOBAL, post_log_len); strncat(post_log, LOG_POST_NAME, post_log_len); strncpy(pre_log, LOG_PATH, pre_log_len); strncat(pre_log, DB_GLOBAL, pre_log_len); strncat(pre_log, LOG_PRE_NAME, pre_log_len); switch (cmd){ case LOG_WRITE_PRE: debug_out(4, "log: In LOG_WRITE_PRE\n"); pre_file = fopen(pre_log, "a"); if(pre_file != NULL) debug_out(4, "log: Opened file '%s'\n", pre_log); else { debug_out(4, "log: Could not open file '%s'\n", pre_log); ret = -1; break; } WriteLogEntry(pre_file, id_in, *commands); debug_out(4, "log: logentry written to file\n"); break; case LOG_WRITE_POST: debug_out(4, "log: In LOG_WRITE_POST\n"); post_file = fopen(post_log, "a"); if(post_file != NULL) debug_out(4, "log: Opened file '%s'\n", post_log); else { debug_out(4, "log: Could not open file '%s'\n", post_log); ret = -1; break; } WriteLogEntry(post_file, id_in, *commands); debug_out(4, "log: logentry written to file\n"); break; case LOG_READ_POST: post_file = fopen(post_log, "r"); if(post_file != NULL) { if(ReadLogEntry(&post_file, &id_in, commands) == -1) { *id_out = LOG_NO_ID; ret = -1; } } break; case LOG_READ_PRE: pre_file = fopen(pre_log, "r"); if(pre_file != NULL) { if(ReadLogEntry(&pre_file, &id_in, commands) == -1) { *id_out = LOG_NO_ID; ret = -1; } } break; case LOG_LAST_ID: if(id_out != NULL) { ret = GetLastId(pre_log, post_log, id_out); } else ret = -1; break; case LOG_GET_NEXT_PRE_ID: if(id_out != NULL) *id_out = GetNextId(pre_log, id_in); else ret = -1; break; case LOG_GET_NEXT_POST_ID: if(id_out != NULL) *id_out = GetNextId(post_log, id_in); else ret = -1; break; case LOG_CHECK_ID: break; default: ret = -1; break; } if(pre_file) { fclose(pre_file); } if(post_file) { fclose(post_file); } return ret; }