Problem with dynamic temp-table. Exceeding temp-table limit 32762

bigwill

Member
Hi all.

I have a program that is called from an appserver routine. It fetches data from multiple tables (specified by user) and returned data as xml to a .net program. I have recently received an error that number of active temp-tables have reached a limit 32762. Am i not deleting objects correct.

For each of my tables i have a own procedure that creates a dynamic temp-table (like), fills the temp-table and then returns the buffer. This buffer is then added to the dataset and on the end, the dataset is written as xml as output (longchar).
I have attached a example of what i do. Am i doing something wrong here ?? Is it enough to delete the dataset ?

Code:
function GetExternalTable returns handle(input iph as handle):
                                  
  /* Create temp-table */
  def var hTable as handle no-undo.
  create temp-table hTable.
 
  /* Add all fields one by one since i have to check extents, datatypes etc etc . */
  def var i as int no-undo.
  def var j as int no-undo.
  def var f as char no-undo.
  do i = 1 to iph:NUM-FIELDS:
    hTable:ADD-NEW-FIELD(iph:buffer-field(i):name,
                        (if iph:buffer-field(i):DATA-TYPE = "Date" then "DateTime" else iph:buffer-field(i):DATA-TYPE), /* date->datetime */
                         0,'',iph:buffer-field(i):DEFAULT-VALUE,iph:buffer-field(i):LABEL,iph:buffer-field(i):COLUMN-LABEL).
  end.

  hTable:TEMP-TABLE-PREPARE(iph:name). 
  return hTable:Default-buffer-handle.
 
end function.


def var hDataSet as handle no-undo.
def var hBuffer as handle no-undo.

//Create a dataset
create dataset hDataSet.

//Create one dynamic table
assign hBuffer = GetExternalTable(input buffer ActivityComment:handle).  //Table called ActivityComment
/* Fill temp-table */
for each ActivityComment no-lock
  where ActivityComment.ActivityNumber = 123456:
  hBuffer:BUFFER-CREATE().
  hBuffer:buffer-copy(buffer ActivityComment:HANDLE,?,?).
end.
//Add to dataset:
if valid-handle(hBuffer) then
  hDataSet:Add-buffer(hBuffer).
 

//Create second dynamic table
assign hBuffer = GetExternalTable(input buffer Customer:handle).  //Table called customer
/* Fill temp-table */
for each customer no-lock
  where customer.c-custno1 = 987654:
  hBuffer:BUFFER-CREATE().
  hBuffer:buffer-copy(buffer customer:HANDLE,?,?).
end.
//Add to dataset:
if valid-handle(hBuffer) then
  hDataSet:Add-buffer(hBuffer).


//Dataset now contains 2 buffers. Output this to my .NET program using appserver
def var cResultXml as longchar no-undo.
hDataSet:write-xml("Longchar",cResultXml,true,"ISO8859-1",?,true,true).

//Clean up ?? This is my problem. Is this good enough ???
delete object hDataSet.
 

Osborne

Active Member
You also need to delete the dynamic temp-tables as well. You may find this article useful:

 

Stefan

Active Member
Deleting the dataset is sufficient. I find it best to add the buffer directly after creation and to delete the dataset in a finally block.

Code:
function checkLeak returns logical (  
   i_i as int
):

   def var hb as handle no-undo.

   hb = session:first-buffer.

   do while valid-handle( hb ):

      message i_i hb:name.
      hb = hb:next-sibling.

   end.

end function.


def var hds as handle no-undo.
def var ht as handle no-undo.
def var hb as handle no-undo.


create dataset hds.
create temp-table ht.
ht:add-new-field( "cc", "character" ).
ht:temp-table-prepare( "tt" ).

hb = ht:default-buffer-handle.

hds:add-buffer( hb ).

checkLeak( 1 ).

delete object hds.

checkLeak( 2 ).
 

bigwill

Member
Deleting the dataset is sufficient. I find it best to add the buffer directly after creation and to delete the dataset in a finally block.

Code:
function checkLeak returns logical ( 
   i_i as int
):

   def var hb as handle no-undo.

   hb = session:first-buffer.

   do while valid-handle( hb ):

      message i_i hb:name.
      hb = hb:next-sibling.

   end.

end function.


def var hds as handle no-undo.
def var ht as handle no-undo.
def var hb as handle no-undo.


create dataset hds.
create temp-table ht.
ht:add-new-field( "cc", "character" ).
ht:temp-table-prepare( "tt" ).

hb = ht:default-buffer-handle.

hds:add-buffer( hb ).

checkLeak( 1 ).

delete object hds.

checkLeak( 2 ).

Tnx. It seems like I have some memoryleaks, bacause after running checkleak i am left with some buffers. But i am having a hard time to delete these. In you add create another table, but dont add it to the dataset. How do you deletete that buffer and table ???
 

Stefan

Active Member
I do not understand how you can have a hard time deleting a buffer. If you create it, you delete it - unless you have added it to a dataset that is deleted.

Are you maybe having a hard time tracking down /which/ create buffer is not being deleted? If so you can use the dynamic object monitor from the debugger / use a logentrytypes setting to log dynamic objects on the AppServer and parse the log (see Progress knowledge base).

Another easy debug technique can be to add something to :private data.

Looking at leaks we have had it has sometimes been accidentally reusing a variable:

Code:
create temp-table ht.
...
create temp-table ht.
...
hds:add-buffer( ht:default-buffer-handle ).
 

bigwill

Member
I do not understand how you can have a hard time deleting a buffer. If you create it, you delete it - unless you have added it to a dataset that is deleted.

Are you maybe having a hard time tracking down /which/ create buffer is not being deleted? If so you can use the dynamic object monitor from the debugger / use a logentrytypes setting to log dynamic objects on the AppServer and parse the log (see Progress knowledge base).

Another easy debug technique can be to add something to :private data.

Looking at leaks we have had it has sometimes been accidentally reusing a variable:

Code:
create temp-table ht.
...
create temp-table ht.
...
hds:add-buffer( ht:default-buffer-handle ).
Thank you. I have now found some of the buffers and deleted them. Do you know if it is possible to find all buffers/queries/prodatasets and then delete them all at once at the end of the program. It could be neat to just run a "Clean" procedure at the end. I tried with this

//Delete dynamic temp-tables not already deleted
ASSIGN hObject = SESSION:FIRST-BUFFER.
DO WHILE hObject <> ?:
ASSIGN hTemp = hObject
hObject = hObject:NEXT-SIBLING.
delete object hTemp:table-handle.
end.

but found out that I can not use session as this is a appserver routing that is run by loads of threads. Is it possible to run a similar code for just this procedure ?

//Lars
 

Stefan

Active Member
No, but you may be able to use a (named) widget-pool.
 
Top