Утечка памяти
 Добавлено: 30.06.2008 11:36:42
Добавлено: 30.06.2008 11:36:42Привет всем!
Пишу качалку под Линух на fpc 2.2.0+Indy. Данные хранятся в СУБД Postgres. Использую потоки.
Ниже представлена главная ф-я работы потока. Алгоритм и процедура работает нормально, только вот происходит утечка памяти вне зависимости есть ошибка при закачке или нет. Помогите разобраться!
  вне зависимости есть ошибка при закачке или нет. Помогите разобраться!
			Пишу качалку под Линух на fpc 2.2.0+Indy. Данные хранятся в СУБД Postgres. Использую потоки.
Ниже представлена главная ф-я работы потока. Алгоритм и процедура работает нормально, только вот происходит утечка памяти
 вне зависимости есть ошибка при закачке или нет. Помогите разобраться!
  вне зависимости есть ошибка при закачке или нет. Помогите разобраться!- Код: Выделить всё
- procedure TGetFile.Execute;
 var
 pwd : pPasswd;
 res: PPGResult;
 OrderDate,FileSize: AnsiString;
 Query: AnsiString;
 AURI: TIdURI;
 i: Byte;
 HeapStat: TFPCHeapStatus;
 LIO : TIdSSLIOHandlerSocketOpenSSL;
 //FLIO: TIdIOHandlerStack;
 LC : TIdCompressorZLib;
 //LHE : EIdHTTPProtocolException;
 finfo: stat;
 begin
 if ((fpGetUID = 0) and (fpGetGID = 0)) then
 begin
 pwd := Getpwnam(run_as_user);
 fpSetGID(pwd^.pw_gid);
 fpSetUID(pwd^.pw_uid);
 end;
 
 write_log('INF: Thread #'+IntToStr(TID)+' is starting.');
 
 {Соединяемся с базой}
 DBconn := PQsetdbLogin(pghost, pgport, Nil, Nil, dbName, login, passwd);
 
 if (PQstatus(DBconn) = CONNECTION_BAD) then
 begin
 Writeln (stderr, PQERRORMessage(DBconn));
 halt(100);
 end;
 
 
 while true do
 begin
 Query:=''; FOrderId:= ''; FNSHD:= ''; URL:=''; OrderDate:=''; FullName:=''; FileSize:='';
 //writeln('Начали #',TID);
 HeapStat:=GetFPCHeapStatus;
 writeln('Начали #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 res := PQexec(DBconn, 'BEGIN');
 PQclear(res);
 Query := 'SELECT a."ID" FROM orders a WHERE a."STATUS" = 1 ORDER BY a."DATE" ASC LIMIT 1 FOR UPDATE NOWAIT';
 res := PQexec(DBconn, PChar(Query));
 if (PQresultStatus(res) <> PGRES_TUPLES_OK) then
 begin
 PQclear(res);
 res := PQexec(DBconn, 'ROLLBACK');
 PQclear(res);
 sleep(2000);
 continue;
 end;
 if (PQntuples(res) = 0) then
 begin
 PQclear(res);
 res := PQexec(DBconn, 'ROLLBACK');
 PQclear(res);
 sleep(2000);
 continue;
 end
 else
 begin
 FOrderId:=PQgetvalue(res,0,0);
 //WriteLn(FOrderId);
 PQclear(res);
 Query:='UPDATE orders SET "STATUS" = 2 WHERE "ID" = '''+FOrderId+'''';
 WriteLn(Query);
 res := PQexec(DBconn, PChar(Query));
 if (PQresultStatus(res) <> PGRES_COMMAND_OK) then
 begin
 PQclear(res);
 PQfinish(DBconn);
 Writeln (stderr, PQERRORMessage(DBconn));
 halt(101);
 end;
 PQclear(res);
 res := PQexec(DBconn, 'COMMIT');
 PQclear(res);
 Query:='select a."URL",a."PORT_ID",a."DATE",a."PATH_FILE",a."FILE_SIZE",a."CUR_POSITION" from orders a where a."ID" = '''+FOrderId+'''';
 //writeln(Query);
 res := PQexec(DBconn, PChar(Query));
 if (PQresultStatus(res) <> PGRES_TUPLES_OK) then
 begin
 PQclear(res);
 PQfinish(DBconn);
 Writeln (stderr, PQERRORMessage(DBconn));
 halt(101);
 end;
 URL := PQgetvalue(res, 0, 0);
 FNSHD := PQgetvalue(res, 0, 1);
 OrderDate := PQgetvalue(res, 0, 2);
 FullName := PQgetvalue(res, 0, 3);
 FileSize := PQgetvalue(res, 0, 4);
 FilePosition := StrToInt(PQgetvalue(res, 0, 5));
 PQclear(res);
 writeln(URL,' ',FNSHD,' ',OrderDate,' ',FullName,' ',FileSize,' ',FilePosition);
 AURI := TIdURI.Create(URL);
 HeapStat:=GetFPCHeapStatus;
 writeln('Create URL #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 if((UpperCase(AURI.Protocol) = 'HTTP') or (UpperCase(AURI.Protocol) = 'HTTPS')) then
 begin
 LIO := TIdSSLIOHandlerSocketOpenSSL.Create;
 HeapStat:=GetFPCHeapStatus;
 writeln('Create LIO #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 LC := TIdCompressorZLib.Create;
 HeapStat:=GetFPCHeapStatus;
 writeln('Create LC #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 try
 IdHTTP1 := TIdHTTP.Create;
 HeapStat:=GetFPCHeapStatus;
 writeln('Create HTTP #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 try
 IdHTTP1.Compressor := LC;
 IdHTTP1.OnWork := WorkEventProc;
 IdHTTP1.OnWorkEnd := WorkEndEventProc;
 IdHTTP1.OnWorkBegin := WorkBegEventProc;
 IdHTTP1.HandleRedirects := True;
 IdHTTP1.Request.UserAgent := 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; INFPath.2; .NET CLR 3.0.04506.648)';
 IdHTTP1.Request.Referer := URL;
 if (AURI.Username <> '') then IdHTTP1.Request.Username := AURI.Username;
 if (AURI.Password <> '') then IdHTTP1.Request.Password := AURI.Password;
 if FileExists(FullName) then
 begin
 DestinationObject := TFileStream.Create(FullName,fmOpenWrite);
 DestinationObject.Seek(FilePosition, soFromBeginning);
 NewFile := False;
 IdHTTP1.Request.Range := IntToStr(FilePosition)+'-';
 end
 else
 begin
 if not DirectoryExists(dbstorage+'/'+FNSHD) then fpMkDir(dbstorage+'/'+FNSHD,511);
 if not DirectoryExists(ExtractFileDir(FullName)) then fpMkDir(ExtractFileDir(FullName),511);
 DestinationObject := TFileStream.Create(FullName,fmCreate);
 NewFile := True;
 end;
 IdHTTP1.IOHandler := LIO;
 IdHTTP1.ConnectTimeOut := 10000;
 IdHTTP1.ReadTimeOut := 30000;
 HeapStat:=GetFPCHeapStatus;
 writeln('Create File #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 IdHTTP1.Get(URL,DestinationObject);
 except
 on E : Exception do
 begin
 if E is EIdHTTPProtocolException then
 begin
 //LHE := E as EIdHTTPProtocolException;
 Query:='UPDATE orders SET "STATUS" = 3 WHERE "ID" = '''+FOrderId+'''';
 res := PQexec(DBconn, PChar(Query));
 PQclear(res);
 if Assigned(DestinationObject) then
 Query:='UPDATE clients SET "COUNT_ERRORS" = "COUNT_ERRORS"+1,"COUNT_DOWN_SIZE" = "COUNT_DOWN_SIZE"+'+IntToStr(DestinationObject.Position)+' WHERE "PORT_ID"='''+FNSHD+''''
 else
 Query:='UPDATE clients SET "COUNT_ERRORS" = "COUNT_ERRORS"+1,"COUNT_DOWN_SIZE" = "COUNT_DOWN_SIZE"+0 WHERE "PORT_ID"='''+FNSHD+'''';
 res := PQexec(DBconn, PChar(Query));
 PQclear(res);
 write_log('ERR: #'+IntToStr(TID)+' '+FOrderId+' '+URL+'. '+IdHTTP1.ResponseText);
 if FileExists(FullName) then
 begin
 fpStat(FullName,finfo);
 //FreeAndNil(DestinationObject);
 if (finfo.st_size = 0) then fpUnLink(FullName);
 end;
 end
 else
 begin
 Query:='UPDATE orders SET "STATUS" = 3 WHERE "ID" = '''+FOrderId+'''';
 res := PQexec(DBconn, PChar(Query));
 PQclear(res);
 if Assigned(DestinationObject) then
 Query:='UPDATE clients SET "COUNT_ERRORS" = "COUNT_ERRORS"+1,"COUNT_DOWN_SIZE" = "COUNT_DOWN_SIZE"+'+IntToStr(DestinationObject.Position)+' WHERE "PORT_ID"='''+FNSHD+''''
 else
 Query:='UPDATE clients SET "COUNT_ERRORS" = "COUNT_ERRORS"+1,"COUNT_DOWN_SIZE" = "COUNT_DOWN_SIZE"+0 WHERE "PORT_ID"='''+FNSHD+'''';
 res := PQexec(DBconn, PChar(Query));
 PQclear(res);
 write_log('ERR: #'+IntToStr(TID)+' '+FOrderId+' '+URL+'. '+E.Message);
 if FileExists(FullName) then
 begin
 fpStat(FullName,finfo);
 DestinationObject.Free;
 if (finfo.st_size = 0) then fpUnLink(FullName);
 end;
 end
 end;
 end;
 finally
 FreeAndNil(DestinationObject);
 HeapStat:=GetFPCHeapStatus;
 writeln('Free file #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 FreeAndNil(IdHTTP1);
 HeapStat:=GetFPCHeapStatus;
 writeln('Free HTTP #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 FreeAndNil(LIO);
 HeapStat:=GetFPCHeapStatus;
 writeln('Free LIO #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 
 FreeAndNil(LC);
 HeapStat:=GetFPCHeapStatus;
 writeln('Free LC #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 {if Assigned(DestinationObject) then DestinationObject.Destroy;
 LIO.Destroy;
 LC.Destroy;
 IdHTTP1.Destroy;}
 write_log('DEBUG: #'+IntToStr(TID)+' Free.');
 end;
 end;
 if((UpperCase(AURI.Protocol) = 'FTP') or (UpperCase(AURI.Protocol) = 'FTPS')) then
 begin
 LIO := TIdSSLIOHandlerSocketOpenSSL.Create;
 LC := TIdCompressorZLib.Create;
 IdFTP1 := TIdFTP.Create;
 try
 IdFTP1.Compressor := LC;
 IdFTP1.IOHandler := LIO;
 IdFTP1.OnWork := WorkEventProc;
 IdFTP1.OnWorkBegin := WorkBegEventProc;
 IdFTP1.OnAfterGet := FTPAfterGet;
 IdFTP1.Passive := True;
 IdFTP1.TransferType := ftBinary;
 IdFTP1.ConnectTimeOut := 10000;
 IdFTP1.TransferTimeout := 30000;
 IdFTP1.Host := AURI.Host;
 if(AURI.Username = '') then IdFTP1.Username := 'anonymous' else IdFTP1.Username := AURI.Username;
 if(AURI.Password = '') then IdFTP1.Password := 'pass@give.me' else IdFTP1.Password := AURI.Password;
 try
 IdFTP1.Connect;
 if IdFTP1.Connected then
 begin
 if (AURI.Path <> '') then IdFTP1.ChangeDir(AURI.Path);
 if FileExists(FullName) then
 begin
 DestinationObject := TFileStream.Create(FullName,fmOpenWrite);
 DestinationObject.Seek(FilePosition, soFromBeginning);
 NewFile := False;
 IdFTP1.Get(AURI.Document,DestinationObject, True);
 end
 else
 begin
 if not DirectoryExists(dbstorage+'/'+FNSHD) then fpMkDir(dbstorage+'/'+FNSHD,511);
 if not DirectoryExists(ExtractFileDir(FullName)) then fpMkDir(ExtractFileDir(FullName),511);
 DestinationObject := TFileStream.Create(FullName,fmCreate);
 NewFile := True;
 //writeln(stderr, AURI.Document);
 IdFTP1.Get(AURI.Document,DestinationObject, True);
 end;
 IdFTP1.Quit;
 end;
 except
 on E : Exception do
 begin
 Query:='UPDATE orders SET "STATUS" = 3 WHERE "ID" = '''+FOrderId+'''';
 res := PQexec(DBconn, PChar(Query));
 PQclear(res);
 if Assigned(DestinationObject) then
 Query:='UPDATE clients SET "COUNT_ERRORS" = "COUNT_ERRORS"+1,"COUNT_DOWN_SIZE" = "COUNT_DOWN_SIZE"+'+IntToStr(DestinationObject.Position)+' WHERE "PORT_ID"='''+FNSHD+''''
 else
 Query:='UPDATE clients SET "COUNT_ERRORS" = "COUNT_ERRORS"+1,"COUNT_DOWN_SIZE" = "COUNT_DOWN_SIZE"+0 WHERE "PORT_ID"='''+FNSHD+'''';
 res := PQexec(DBconn, PChar(Query));
 PQclear(res);
 write_log('ERR: #'+IntToStr(TID)+' '+FOrderId+' '+URL+'. '+E.Message);
 if FileExists(FullName) then fpUnLink(FullName);
 if IdFTP1.Connected then IdFTP1.Quit;
 end
 end;
 finally
 FreeAndNil(DestinationObject);
 FreeAndNil(IdFTP1);
 FreeAndNil(LC);
 FreeAndNil(LIO);
 write_log('DEBUG: #'+IntToStr(TID)+' Free.');
 end;
 end;
 AURI.Free;
 HeapStat:=GetFPCHeapStatus;
 writeln('Free URL #',TID,' ',HeapStat.CurrHeapSize,' ',HeapStat.CurrHeapUsed,' ',HeapStat.CurrHeapFree);
 write_log('DEBUG: #'+IntToStr(TID)+' URL free.');
 end;
 end;
 end;
 
 
 .
 . 
 