Blame | Last modification | View Log | RSS feed
//---------------------------------------------------------------------------#include <vcl.h>#pragma hdrstop#include "UdTransferHistory.h"#include "UdTransfer.h"#include "DataModule.h"#include <dateutils.hpp>//---------------------------------------------------------------------------#pragma package(smart_init)#pragma link "Grids_ts"#pragma link "TSDBGrid"#pragma link "TSGrid"//#pragma link "PERFGRAP"#pragma link "AdvPageControl"#pragma link "AdvGrid"#pragma link "BaseGrid"#pragma link "DBAdvGrd"#pragma link "AdvGrid"#pragma link "BaseGrid"#pragma resource "*.dfm"TUdTransferHistoryForm *UdTransferHistoryForm;namespace{AnsiString GetDurationString( const TDateTime & now, const TDateTime & then ){AnsiString duration;AnsiString text;// Longest duration should be in daysint days = DaysBetween( now, then );__int64 hours = HoursBetween( now, then );__int64 mins = MinutesBetween( now, then );__int64 secs = SecondsBetween( now, then );if( days > 0 ){text.sprintf( "%d day(s), ", days );duration = text;hours = hours % 24;mins = mins % 60;secs = secs % 60;}else if( hours > 0 ){mins = mins % 60;secs = secs % 60;}else if( mins > 0 ){secs = secs % 60;}text.sprintf( "%02Ld:%02Ld:%02Ld", hours, mins, secs );duration += text;return duration;}AnsiString GetDurationString( const int & duration ){TDateTime then = 0;TDateTime now = (double)duration/(24*60*60);return GetDurationString( now, then );}AnsiString FormatNumeric( long double number, int precision = 0 ){return AnsiString::FloatToStrF((long double)number, AnsiString::sffNumber, 18, precision);}typedef enum{COL_ATTRIB = 1,COL_VALUE = 2} TransferDetailsColumns;typedef enum{ROW_SOURCE_PATH = 1,ROW_DESTINATION = 2,ROW_BATCH_SIZE = 3,ROW_END_TIME = 4,ROW_COMMENTS = 5,ROW_RAMP_TYPE = 6,ROW_RAMP_TIME = 7,ROW_DURATION = 8,ROW_FREQUENCY = 9,ROW_GRADIENT = 10,ROW_RECURRING = 11} TransferDetailsRows;}//---------------------------------------------------------------------------__fastcall TUdTransferHistoryForm::TUdTransferHistoryForm(TComponent* Owner): TForm(Owner), m_manager( NULL ){}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::btAddClick(TObject *Sender){if( UdTransferForm->ShowForm( m_manager ) == mrOk ){RefreshHistory();}}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::btnAbortClick(TObject *Sender){if( MessageDlg("Are you sure you want to abort this transfer task?",mtConfirmation, TMsgDlgButtons() << mbNo << mbYes, 0 ) == mrYes ){UdTransferTask task;task.id = m_curTransferNum;if( m_manager->GetTaskDetails( task ) ){AnsiString comment;int status = gridHistory->DataSource->DataSet->FieldByName("status")->AsInteger;task.state = UdTransferAborted;if( status == UdTransferPending ){comment = "Transfer aborted before processing started.";}else if( status == UdTransferInProgress ){if( !task.recurring ){comment = "Transfer aborted during processing.";}else{// Stopping a recurring task is not really an errorcomment = "User stopped recurring transfers during processing.";task.state = UdTransferCompleted;}}m_manager->UpdateTask( task, comment );}else{// Only way this could happen is if we are aborting a task set as// in progress after which the program crashed. Simply update the status flag.TADOQuery * txnquery = new TADOQuery(NULL);if( txnquery == NULL ) return;txnquery->Connection = Data_Module->IntegrationDBConnection;AnsiString sql_statement;sql_statement.sprintf("update TRANSFER_HISTORY set "" STATUS = %d, "" END_TIME = sysdate ""where TRANSFER_NO = %d",(int)UdTransferAborted,m_curTransferNum);txnquery->SQL->Text = sql_statement;txnquery->ExecSQL();txnquery->Close();delete txnquery;RefreshHistory();}}}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::gridHistoryCellLoaded(TObject *Sender, int DataCol, Variant &DataRow, Variant &Value){// Format some of the loaded grid dataif( DataCol == 5 ) // Status{switch( gridHistory->DataSource->DataSet->FieldByName("status")->AsInteger ){case UdTransferCompleted: Value = "Completed"; break;case UdTransferFailed: Value = "Failed"; break;case UdTransferAborted: Value = "Aborted"; break;case UdTransferInProgress: Value = "In Progress"; break;case UdTransferPending: Value = "Pending"; break;};}}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::gridHistoryRowChanged(TObject *Sender, Variant &OldRow, Variant &NewRow){m_curTransferNum = gridHistory->DataSource->DataSet->FieldByName("transfer_no")->AsInteger;LoadTransferDetails();LoadTransferStatistics();try {bool isOwner = (gridHistory->DataSource->DataSet->FieldByName("username")->AsString == m_manager->GetUsername());switch( gridHistory->DataSource->DataSet->FieldByName("status")->AsInteger ){case UdTransferCompleted:case UdTransferFailed:case UdTransferAborted:btnAbort->Enabled = false;break;case UdTransferInProgress:case UdTransferPending:btnAbort->Enabled = isOwner;break;};}catch( EDatabaseError & e ){btnAbort->Enabled = false;}}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::ShowForm(TObject *Sender){btnAbort->Enabled = false;m_curTransferNum = 0;gridDetails->Cells[COL_ATTRIB][ROW_SOURCE_PATH] = "Source Path";gridDetails->Cells[COL_ATTRIB][ROW_DESTINATION] = "Destination";gridDetails->Cells[COL_ATTRIB][ROW_BATCH_SIZE] = "Batch Size";gridDetails->Cells[COL_ATTRIB][ROW_END_TIME] = "End Time";gridDetails->Cells[COL_ATTRIB][ROW_COMMENTS] = "Comments";gridDetails->Cells[COL_ATTRIB][ROW_RAMP_TYPE] = "Ramp Type";gridDetails->Cells[COL_ATTRIB][ROW_RAMP_TIME] = "Ramp Time";gridDetails->Cells[COL_ATTRIB][ROW_DURATION] = "Duration";gridDetails->Cells[COL_ATTRIB][ROW_FREQUENCY] = "Frequency";gridDetails->Cells[COL_ATTRIB][ROW_GRADIENT] = "Ramp Gradient";gridDetails->Cells[COL_ATTRIB][ROW_RECURRING] = "Recurring Test";qryTransferHistory->Active = true;gridHistory->DataSource = dsTransferHistory;}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::LoadTransferDetails(){// Get the data and load the new entriesTADOQuery * txnquery = new TADOQuery(NULL);if( txnquery == NULL ) return;txnquery->Connection = Data_Module->IntegrationDBConnection;AnsiString sql_statement;sql_statement.sprintf("select SOURCE_PATH, DESTINATION, BATCH_SIZE, END_TIME, COMMENTS, "" RAMP_TYPE, RAMP_TIME, DURATION, FREQUENCY, RAMP_GRADIENT, RECURRING ""from TRANSFER_HISTORY ""where TRANSFER_NO = %d",m_curTransferNum);txnquery->SQL->Text = sql_statement;txnquery->Open();if( !txnquery->Eof ){UdTransferTask task;AnsiString comments;TDateTime endTime;task.sourcePath = txnquery->FieldByName("SOURCE_PATH")->AsString;task.destination = txnquery->FieldByName("DESTINATION")->AsString;task.batchSize = txnquery->FieldByName("BATCH_SIZE")->AsInteger;endTime = txnquery->FieldByName("END_TIME")->AsDateTime;comments = txnquery->FieldByName("COMMENTS")->AsString;task.rampType = (RampTestType)txnquery->FieldByName("RAMP_TYPE")->AsInteger;task.rampTime = txnquery->FieldByName("RAMP_TIME")->AsDateTime;task.duration = txnquery->FieldByName("DURATION")->AsInteger;task.frequency = txnquery->FieldByName("FREQUENCY")->AsInteger;task.gradient = txnquery->FieldByName("RAMP_GRADIENT")->AsFloat;task.recurring = (txnquery->FieldByName("RECURRING")->AsInteger > 0);SetTransferDetails( task, endTime, comments );}delete txnquery;}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::ResetTransferDetails(){gridDetails->ClearCols( 3, 1 );}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::ResetTransferStatistics(){bool isTransferRunning = false;if( (m_curTransferNum != 0) &&gridHistory->DataSource->DataSet->Active ){int status = gridHistory->DataSource->DataSet->FieldByName("status")->AsInteger;isTransferRunning = ((status == UdTransferInProgress) ||(status == UdTransferPending));}lblNumFiles->Caption = "N/A";lblBytes->Caption = "N/A";lblTransferTime->Caption= "N/A";lblFilesPerSec->Caption = "N/A";lblBytesPerSec->Caption = "N/A";lblPercent->Caption = "0%";pbCompleted->Position = 0;lblPercent->Visible = isTransferRunning;pbCompleted->Visible = isTransferRunning;lblProgress->Visible = isTransferRunning;seriesBatches->Clear();chartBatchSize->LeftAxis->Automatic = false;chartBatchSize->BottomAxis->Automatic = false;chartBatchSize->LeftAxis->SetMinMax( 0, 10 );chartBatchSize->BottomAxis->SetMinMax( 1, 10 );}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::SetTransferDetails( const UdTransferTask & task,const TDateTime & endTime,const AnsiString & comments ){ResetTransferDetails();gridDetails->Cells[COL_VALUE][ROW_SOURCE_PATH] = task.sourcePath;gridDetails->Cells[COL_VALUE][ROW_DESTINATION] = task.destination;gridDetails->Cells[COL_VALUE][ROW_BATCH_SIZE] = task.batchSize;gridDetails->Cells[COL_VALUE][ROW_COMMENTS] = comments;gridDetails->Cells[COL_VALUE][ROW_DURATION] = GetDurationString( task.duration );gridDetails->Cells[COL_VALUE][ROW_FREQUENCY] = GetDurationString( task.frequency );gridDetails->Cells[COL_VALUE][ROW_END_TIME] =((int)endTime == 0) ? "Not Finished" : endTime.DateTimeString().c_str();gridDetails->Cells[COL_VALUE][ROW_RAMP_TIME] =(task.rampType == RampTestDisabled) ? "Not Applicable" : task.rampTime.DateTimeString().c_str();gridDetails->Cells[COL_VALUE][ROW_GRADIENT] =(task.rampType == RampTestByDemand) ? FloatToStr(task.gradient).c_str() : "Not Applicable";gridDetails->Cells[COL_VALUE][ROW_RECURRING] =(task.recurring ? "True" : "False");AnsiString rampType = "Unknown";switch( task.rampType ){case RampTestDisabled: rampType = "Batch Transfer"; break;case RampTestByDemand: rampType = "Ramp by Demand"; break;case RampTestByRatio: rampType = "Ramp by Ratio"; break;}gridDetails->Cells[COL_VALUE][ROW_RAMP_TYPE] = rampType;}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::LoadTransferStatistics(){ResetTransferStatistics();UpdateTransferStatistics();}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::UpdateTransferStatistics(){UdTransferStatistics stats;if( m_manager->GetTaskStatistics( m_curTransferNum, stats ) ){int percentDone = 0;bool displayDurations = true;// If the task is pending, duration statistics are not valid yettry{int status = gridHistory->DataSource->DataSet->FieldByName("status")->AsInteger;if( status == UdTransferPending ){lblTransferTime->Caption = "Pending ...";displayDurations = false;}}catch( EDatabaseError & e ){displayDurations = false;}// Set processed/total files statsif( stats.completed ){lblNumFiles->Caption = FormatNumeric( stats.processedFiles );lblBytes->Caption = FormatNumeric( stats.processedBytes );displayDurations = (stats.processedFiles > 0);}else if( stats.totalFiles > 0 ){// Stats provided in realtime (non-complete) have more info to displaylblBytes->Caption = FormatNumeric( stats.processedBytes );lblNumFiles->Caption = FormatNumeric( stats.processedFiles % stats.totalFiles )+ " / " + FormatNumeric( stats.totalFiles );if( stats.processedFiles > stats.totalFiles ){AnsiString recurses = lblNumFiles->Caption;recurses += " (x" + IntToStr( stats.processedFiles / stats.totalFiles ) + ")";lblNumFiles->Caption = recurses;}if( gridDetails->Cells[COL_VALUE][ROW_RECURRING] != "True" ){percentDone = (((stats.processedFiles % stats.totalFiles)*100) / stats.totalFiles);}}// Fill in the chart detailsif( !stats.batches.empty() ){seriesBatches->Clear();chartBatchSize->LeftAxis->Automatic = true;chartBatchSize->BottomAxis->Automatic = true;BatchSizeItem batch = stats.batches.begin();for( int count = 1; batch != stats.batches.end(); batch++, count++ ){seriesBatches->AddXY( count, (double)(*batch)/1024, "", clBlue );}}// Dont display durations for transfers with no files sentif( displayDurations ){try {TDateTime startTime = stats.startTime;TDateTime endTime = TDateTime::CurrentDateTime();if( stats.completed ) endTime = gridDetails->Cells[COL_VALUE][ROW_END_TIME];lblTransferTime->Caption = GetDurationString( endTime, startTime );__int64 duration = SecondsBetween( endTime, startTime );if( duration > 0 ){lblFilesPerSec->Caption = FormatNumeric( (double)stats.processedFiles / duration, 3 );lblBytesPerSec->Caption = FormatNumeric( (double)stats.processedBytes / duration, 3 );}else{lblFilesPerSec->Caption = FormatNumeric( (double)stats.processedFiles, 3 );lblBytesPerSec->Caption = FormatNumeric( (double)stats.processedBytes, 3 );}if( !stats.completed ){__int64 completion = SecondsBetween( stats.endTime, startTime );if( completion > 0 ){if( duration > completion ){percentDone = 100;}else{int timePercent = (((duration % completion)*100) / completion);if( timePercent > percentDone ){percentDone = timePercent;}}}}}catch( EConvertError & e ){// If we're here, it means we have a case where we are accessing// an in-progress task after a program crash (end time will fail to convert// as it is just text). We wont know the end time in anycase, so just// ignore it and display "N/A"s.}catch( EDatabaseError & e ) {} // Ignore}// Set the progress bar if required. Take the max between files remaining// (if not recurring task), and the time remaining till completion.if( !stats.completed ){if( percentDone > 100 ) percentDone = 100;lblPercent->Caption = IntToStr( percentDone ) + "%";pbCompleted->Position = percentDone;}}}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::gridRowResized(TObject *Sender, int RowColnr){// Ensure row height is not less than the font sizeint minHistoryRowSize = (gridHistory->Font->Size + 5);if( gridHistory->DefaultRowHeight < minHistoryRowSize ){gridHistory->DefaultRowHeight = minHistoryRowSize;}int minDetailsRowSize = (gridDetails->Font->Size +5);if( gridDetails->DefaultRowHeight < minDetailsRowSize ){gridDetails->DefaultRowHeight = minDetailsRowSize;}}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::btnCloseClick(TObject *Sender){Visible = false;}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::btnRefreshClick(TObject *Sender){RefreshHistory();}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::TimerTick(TObject *Sender){if( (tabDetails->ActivePageIndex == 1) &&qryTransferHistory->Active ){int status = gridHistory->DataSource->DataSet->FieldByName("status")->AsInteger;if( (status == UdTransferPending || status == UdTransferInProgress) ){UpdateTransferStatistics();}}}//---------------------------------------------------------------------------void __fastcall TUdTransferHistoryForm::RefreshHistory(){qryTransferHistory->Active = false;qryTransferHistory->Active = true;/*if( gridHistory-> ){gridHistory->CurrentCell->MoveTo( 1, 1 );}LoadTransferDetails();LoadTransferStatistics();*/}