You are not logged in.
Pages: 1
Hi,
I have a TSQLRestServerDB declared as such:
TSQLTESTRestServerDB = class(TSQLRestServerDB)
public
onMount: TSQLRestServerCallBack;
onUnmount: TSQLRestServerCallBack;
published
procedure Mount(Ctxt: TSQLRestServerURIContext);
procedure Unmount(Ctxt: TSQLRestServerURIContext);
end;
And my main server class as such:
TMainServer = class(TObject)
protected
procedure SetLog;
procedure Connect;
function OnConnect(Sender: TSQLRestServer; Session: TAuthSession; Ctxt: TSQLRestServerURIContext): boolean;
function OnDisconnect(Sender: TSQLRestServer; Session: TAuthSession; Ctxt: TSQLRestServerURIContext): boolean;
function OnUpdate(Sender: TSQLRestServer; Event: TSQLEvent; aTable: TSQLRecordClass; const aID: TID; const aSentData: RawUTF8): boolean;
public
fLog: TSynLog;
fMODELBDD: TSQLModel;
fBDD: TSQLDataBase;
fREST: TSQLTESTRestServerDB;
fRestTab: TObjectDictionary<RawUTF8, TSQLRestServerDB>;
fHTTPServer: TSQLHttpServer;
constructor Create;
destructor Destroy; override;
procedure MountREST(Ctxt: TSQLRestServerURIContext);
procedure UnmountREST(Ctxt: TSQLRestServerURIContext);
end;
So I set up my connection like this:
fMODELBDD := TSQLModel.Create([]);
try
fBDD := TSQLDataBase.Create(ExeVersion.ProgramFilePath+'MainTest.s3db', '', SQLITE_OPEN_CREATE or SQLITE_OPEN_READWRITE);
try
fREST := TSQLTESTRestServerDB.Create(fMODELBDD, fBDD, True);
try
fREST.CreateMissingTables();
fREST.OnSessionCreate := OnConnect;
fREST.OnSessionClosed := OnDisconnect;
fREST.OnUpdateEvent := OnUpdate;
//My events
fREST.onMount := MountREST;
fREST.onUnmount := UnmountREST;
// /
fHTTPServer := TSQLHttpServer.Create(AnsiString('8080'), [fREST], '+', useHttpApiRegisteringURI);
try
fRestTab := TObjectDictionary<RawUTF8, TSQLRestServerDB>.Create([doOwnsValues]);
fLog.Add.Log(sllInfo, ' - Init ok');
fLog.Add.Log(sllInfo, ' - Server set on port ::8080::');
except
FreeAndNil(fHTTPServer);
end;
except
FreeAndNil(fREST);
end;
except
FreeAndNil(fBDD);
end;
except
FreeAndNil(fMODELBDD);
end;
MountREST:
procedure TMainServer.MountREST(Ctxt: TSQLRestServerURIContext);
var ref: RawUTF8;
begin
if UrlDecodeNeedParameters(Ctxt.Parameters, 'ref') then begin
ref := Ctxt['ref'];
fLog.Enter();
fLog.Add.Log(sllInfo, 'Ref: '+ref);
if fRestTab.ContainsKey(ref) then begin
//If already mounted
Ctxt.Results([ref]);
end else begin
//if not
fRestTab.Add(ref,
TSQLRestServerDB.Create(
TSQLModel.Create([], ref),
TSQLDataBase.Create(ExeVersion.ProgramFilePath+ref+'.s3db', '', SQLITE_OPEN_CREATE or SQLITE_OPEN_READWRITE), True)
);
try
//fRestTab.Items[refUniqueServeur].Model.Owner := fRestTab.Items[refUniqueServeur]; //Is this usefull?
fRestTab.Items[ref].CreateMissingTables;
if fHTTPServer.AddServer(fRestTab.Items[ref]) then begin
Ctxt.Results([ref]);
fLog.Add.Log(sllInfo, ' ++ '''+ref+''' mounted');
end else begin
fLog.Add.Log(sllError, ' xx '''+ref+''' couldn''t be mounted');
end;
except
fRestTab.Items[ref].DB.DBClose;
fRestTab.Items[ref].DB.Free;
fRestTab.Items[ref].Model.Free;
fRestTab.Remove(ref);
fLog.Add.Log(sllError, 'failure while mounting: '+ref);
end;
end;
end else begin
fLog.Add.Log(sllError, 'Mount called without parameter');
Ctxt.Results(['ERREUR: ref missing']);
end;
end;
and very quickly how i clean my REST item when calling UnmountREST:
if fHTTPServer.RemoveServer(fRestTab.Items[ref]) then begin
fRestTab.Items[ref].DB.DBClose;
fRestTab.Items[ref].DB.Free;
fRestTab.Items[ref].Model.Free;
fRestTab.Remove(ref); //autoFree because of [doOwnsValues]
fLog.Add.Log(sllInfo, ' -- '''+ref+''' unmounted');
end else begin
fLog.Add.Log(sllError, ' xx '''+ref+''' couldn''t be unmounted');
end;
And now for my memory leak:
If I do with my client something like this:
//Connection to the first REST
fClient1 := TSQLHttpClient.Create('localhost', '8080', TSQLModel.Create([]), false);
if not fClient1.ServerTimeStampSynchronize then
raise Exception.Create('Fail while timestamp synchro');
if not fClient1.SetUser('Admin', 'synopse') then
raise Exception.Create('Fail while SetUser');
//Call MountREST without connecting to it
fClient1.CallBackGetResult('Mount', ['ref', 'TEST002']);
//Then unmount and disconnect
fClient1.CallBackGetResult('Unmount', ['ref', 'TEST002']);
FreeAndNil(fClient1);
I have absolutely no problem when exiting the server app, no memory leak.
But if I init a connection with the second mounted REST like this
//Connection to the first REST
fClient1 := TSQLHttpClient.Create('localhost', '8080', TSQLModel.Create([]), false);
if not fClient1.ServerTimeStampSynchronize then
raise Exception.Create('Fail while timestamp synchro');
if not fClient1.SetUser('Admin', 'synopse') then
raise Exception.Create('Fail while SetUser');
//Call MountREST and connect to it
fClient1.CallBackGetResult('Mount', ['ref', 'TEST002']);
fClient2 := TSQLHttpClient.Create('localhost', '8080', TSQLModel.Create([], 'TEST002'), false);
if not fClient2.ServerTimeStampSynchronize then
raise Exception.Create('CLIENT2: Fail while timestamp synchro');
if not fClient2.SetUser('Admin', 'synopse') then
raise Exception.Create('CLIENT2: Fail while SetUser');
//Then disconnect, unmount and disconnect again
FreeAndNil(fClient2);
fClient1.CallBackGetResult('Unmount', ['ref', 'TEST002']);
FreeAndNil(fClient1);
I have memory leak of type unknow.
Why is it only when i'm connecting client to it? Am I doing something wrong?
If you need sample app or the memory leak file just tell me.
Thanks all for your help
Offline
Where is the memory leak? On the client or the server side?
What does FastMM4 (or other tool) says about the memory leak types, in FULLDEBUGMODE?
It could say something more than "type unknown".
My guess is that your "unmount" implementation (which is not shown here) is leaking memory.
Also note that your code is not thread-safe, so on production, it would fail. But I guess that it won't affect your client code yet (which is blocking).
And that using "fRestTab.Items[ref]" everywhere in your code is slow and error more than a dedicated local variable.
Offline
Thanks for your reply and sorry for the lack of information.
The memory leak is on server side.
There is my full Unmount procedure
procedure TMainServer.UnmountREST(Ctxt: TSQLRestServerURIContext);
var ref: RawUTF8;
begin
if UrlDecodeNeedParameters(Ctxt.Parameters, 'ref') then begin
ref := Ctxt['ref'];
fLog.Enter();
fLog.Add.Log(sllInfo, 'Ref: '+ref);
if fHTTPServer.RemoveServer(fRestTab.Items[ref]) then begin
with fRestTab.Items[ref] do begin
DB.DBClose;
DB.Free;
Model.Free;
end;
fRestTab.Remove(ref); //autoFree because of [doOwnsValues]
fLog.Add.Log(sllInfo, ' -- '''+ref+''' unmounted');
end else begin
fLog.Add.Log(sllError, ' xx '''+ref+''' couldn''t be unmounted');
end;
end else begin
fLog.Add.Log(sllError, 'Unmout called without parameter');
Ctxt.Results(['ERREUR: ref missing']);
end;
end;
I was just using System.ReportMemoryLeaksOnShutdown := true,
but now I have added FastMM4 with FullDebugMode, and the objects who leaks are still marked as "unknow". Should I enable other options from FastMM?
The thing is, I only have memory leaks when i'm connecting client to the mounted REST, but none if I just mount then unmount REST.
Thanks for your advices, this is juste a sample server to show you my problem, I'm going to add some lock to MountREST and UnmountREST. And I will change the access method for my REST instance, thanks!
Offline
I don't know if that relevant, but i've noticed something: if I delete the second .s3db file (the one from the mounted REST), and then launch the server app and client and connect to first REST, mount second REST, unmount it (without connecting to it) and disconnect, when closing server app I also have a memory leak, but not if the .s3db is already created.
Here is a link to the report for this: http://pastebin.com/0ntcVirL
And a link to the report when I connect the client to the mounted REST, my initial problem: http://pastebin.com/ZFLcDcZn
Everything point to the Mount and Unmount methods, but i can't see what am I doing wrong for freeing the REST instance?
Or maybe is there a better way to mount database at demand with your framework?
Thanks.
Offline
You are using a TSQLRestServerDB.Create constructor which never releases its internal TSQLDataBase instance.
Either
- you add the TSQLDataBase instance to your list,
- or you set the aHandleUserAuthentication parameter to TRUE
- or you use the regular TSQLRestServerDB.Create constructor with direct database aDBFileName.
Offline
Great, thanks you! I've tried with direct database file name and no leak anymore.
But to remind, I was constructing my TSQLRestServerDB like this
TSQLRestServerDB.Create(
TSQLModel.Create([], ref),
TSQLDataBase.Create(ExeVersion.ProgramFilePath+refUniqueServeur+'.s3db', '', SQLITE_OPEN_CREATE or SQLITE_OPEN_READWRITE),
True)
So aHandleUserAuthentication is already set to true. And I was cleaning it like this
with fRestTab.Items[ref] do begin
DB.DBClose;
DB.Free;
Model.Free;
end;
fRestTab.Remove(ref);
DB.DBClose + DB.Free shouldn't be freeing my Database instance?
Anyway, thanks a lot, problem solved! ; )
Offline
Oh okay, this makes more sense, you should REST ; ) thanks again
Also, should I do
MyRestServer.Model.Owner := MyRestServer;
or is this nonsense?
Offline
Pages: 1