GSI Object Oriented Online Offline (Go4)  GO4-5.3.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
TGo4BufferQueue.cxx
Go to the documentation of this file.
1 // $Id: TGo4BufferQueue.cxx 1433 2015-05-19 13:01:35Z linev $
2 //-----------------------------------------------------------------------
3 // The GSI Online Offline Object Oriented (Go4) Project
4 // Experiment Data Processing at EE department, GSI
5 //-----------------------------------------------------------------------
6 // Copyright (C) 2000- GSI Helmholtzzentrum f�r Schwerionenforschung GmbH
7 // Planckstr. 1, 64291 Darmstadt, Germany
8 // Contact: http://go4.gsi.de
9 //-----------------------------------------------------------------------
10 // This software can be used under the license agreements as stated
11 // in Go4License.txt file which is part of the distribution.
12 //-----------------------------------------------------------------------
13 
14 #include "TGo4BufferQueue.h"
15 
16 #include "TROOT.h"
17 #include "TClass.h"
18 #include "TMutex.h"
19 #include "TFile.h"
20 #include "TGo4Buffer.h"
21 #include "RVersion.h"
22 #include "Riostream.h"
23 
24 
25 #include "TGo4Socket.h"
26 #include "TGo4RuntimeException.h"
27 #include "TGo4Log.h"
28 #include "TGo4LockGuard.h"
29 
30 #if ROOT_VERSION_CODE > ROOT_VERSION(4,3,2)
31  const Int_t TGo4BufferQueue::fgiISOWNER = TBuffer::kIsOwner;
32 #else
33  const Int_t TGo4BufferQueue::fgiISOWNER = BIT(14);
34 // we emulate the protected owner flag of the TBuffer class, needed for reallocation!
35 #endif
36 
37 
39  TGo4Queue("Default buffer queue"),
40  fxBufferList(0),
41  fxFreeList(0),
42  fxBufferMutex(0),
43  fiOverflowcount(0),
44  fiMaxBuffers(10)
45 {
46  GO4TRACE((14,"TGo4BufferQueue::TGo4BufferQueue()", __LINE__, __FILE__));
47 
48  InitBuffers();
49 }
50 
52  TGo4Queue(name),
53  fxBufferList(0),
54  fxFreeList(0),
55  fxBufferMutex(0),
56  fiOverflowcount(0),
57  fiMaxBuffers(10)
58 {
59  GO4TRACE((14,"TGo4BufferQueue::TGo4BufferQueue(const char*)", __LINE__, __FILE__));
60 
61  InitBuffers();
62 }
63 
65 
66 {
67  GO4TRACE((14,"TGo4BufferQueue::InitBuffers()", __LINE__, __FILE__));
68  TGo4LockGuard mainguard;
69  fxBufferList = new TList; // list owning all buffers
70  fxFreeList = new TList; // list indicating the free buffers
71  fxBufferMutex = new TMutex;
72  for (Int_t i=0; i< fiMaxBuffers; ++i) {
73  TBuffer* buf = NewEntry();
74  fxBufferList->Add(buf);
75  fxFreeList->Add(buf);
76  }
77 }
78 
80 {
81  GO4TRACE((14,"TGo4BufferQueue::~TTGo4BufferQueue()", __LINE__, __FILE__));
82 
83  fxBufferList->Delete();
84  TCollection::EmptyGarbageCollection();
85 
86  delete fxFreeList; fxFreeList = 0;
87  delete fxBufferList; fxBufferList = 0;
88  delete fxBufferMutex; fxBufferMutex = 0;
89 }
90 
92 {
93  GO4TRACE((19,"TGo4BufferQueue::WaitBuffer()", __LINE__, __FILE__));
94  TObject* ob = Wait();
95  return dynamic_cast<TBuffer*> ( ob );
96 }
97 
99 {
100  GO4TRACE((19,"TGo4BufferQueue::WaitObjectFromBuffer()", __LINE__, __FILE__));
101  TObject* obj=0;
102  TBuffer* buffer = WaitBuffer();
103  if(buffer) {
104  {
105  //std::cout << "BBBBBBBBBBBBBBB TGo4BufferQueue::WaitObjectFromBuffer() before mainguard "<< std::endl;
106  TGo4LockGuard mainguard;
107  // lock go4 main mutex for streaming
108  TDirectory* savdir=gDirectory;
109  gROOT->cd(); // be sure to be in the top directory when creating histo
110  buffer->SetReadMode();
111  //std::cout << " Reading object from buffer..."<< std::endl;
112  buffer->Reset();
113  buffer->InitMap();
114  // note: root version 3.05/02 crashes again when unknown class
115  // shall be read; this was working in 3.03/09
116  // therefore, we put in our own check again from revision 1.23
117  TClass* cl = buffer->ReadClass();
118  //std::cout << "buffer queue "<< GetName() <<" :waitobject, got Class: " << cl << std::endl;
119  if(cl == (TClass*) -1)
120  {
121  // case of unknown class
122  std::cout << " Could not receive object of unknown class on buffer queue "<<GetName() <<" !!!" <<std::endl;
123  obj=0;
124  } else {
125  // if(cl)
126  // std::cout << "Classname: " << cl->GetName() << std::endl;
127  // std::cout << "Reading object from buffer..."<< std::endl;
128  buffer->Reset();
129  obj = buffer->ReadObject(cl);
130  }
131  if(savdir) savdir->cd();
132  } // TGo4LockGuard
133  FreeBuffer(buffer); // give internal buffer back to queue
134  } // if(buffer)
135 
136  return obj;
137 }
138 
139 void TGo4BufferQueue::AddBuffer(TBuffer * buffer, Bool_t clone)
140 {
141  GO4TRACE((19,"TGo4BufferQueue::AddBuffer(TBuffer*, Bool_t)", __LINE__, __FILE__));
142 
143  TBuffer* entry=0;
144  Bool_t entryisnew=kFALSE;
145  if(clone)
146  {
147  //std::cout <<"BBBBBBBBBBBBBBB TGo4BufferQueue "<< GetName()<< " before lockguard of buffer mutex "<<fxBufferMutex<<std::endl;
149  entry= dynamic_cast<TBuffer*>(fxFreeList->Remove(fxFreeList->First()));
150  // get next free buffer
151  if(entry==0)
152  {
153  // no buffer entry there, we create one
154  TGo4Log::Debug(" Buffer Queue adding new internal buffer... ");
155  //std::cout <<"Buffer Queue: creating new internal buffer... "<< GetName();
156 
157  entry=NewEntry();
158  //std::cout <<"BBBBBBBBBBBBBBB TGo4BufferQueue "<< GetName()<< " before Add to free list... "<<std::endl;
159 
160  fxBufferList->Add(entry); // add to list of existing buffers
161  // need not add new buffer to list of free buffers
162  entryisnew=kTRUE;
163  fiMaxBuffers++;
164  //std::cout <<"buffers:"<<fiMaxBuffers <<", "<< fiMaxBuffers*TGo4Socket::fgiBUFINITSIZE << std::endl;
165  }
166  else
167  {
168  // ok, we have a buffer to clone
169  }
170 
171  Int_t srcsize=buffer->BufferSize();
172  Int_t destsize=entry->BufferSize();
173  if (srcsize>destsize)
174  {
175  Realloc(entry,destsize,srcsize);
176  destsize=srcsize;
177  }
178  else
179  {
180  // buffer big enough, proceed
181  }
182  char* source= buffer->Buffer();
183  char* destination= entry->Buffer();
184  memcpy(destination,source,destsize);
185  //std::cout <<"))))))))))Buffer Queue: copied "<< destsize <<"bytes to buffer field" << std::endl;
186  Int_t messlen = buffer->Length(); // compatible with root TMessage protocol
187  entry->SetBufferOffset(messlen);
188  entry->SetByteCount(0);
189  } // if(clone)
190  else
191  {
192  entry=buffer;
193  }
194  //std::cout <<"Bufferqueue AB adding buffer "<< entry << std::endl;
195 
196  try
197  {
198  //std::cout <<"BBBBBBBBBBBBBBB TGo4BufferQueue "<< GetName()<< " before Add to queue... "<<std::endl;
199  Add(entry);
200  //std::cout <<"BBBBBBBBBBBBBBB after Add to queue. "<<std::endl;
201  }
202  catch(TGo4RuntimeException ex)
203  {
204  std::cout << "Buffer queue "<< GetName()<<" is full, dropping new entry "<< entry <<" !!!" << std::endl;
205  if(entryisnew)
206  {
208  fxBufferList->Remove(entry); // remove new entry again from pool
209  delete entry;
210  }
211  }
212 }
213 
215 {
216  GO4TRACE((12,"TGo4BufferQueue::AddBufferFromObject(TObject*)", __LINE__, __FILE__));
217  if(object==0) return;
218  TGo4LockGuard mainguard;
219  TBuffer* entry = 0;
220  entry = new TGo4Buffer(TBuffer::kWrite);
221  //std::cout <<" Buffer queue ABFO created buffer "<<entry << std::endl;
222  TFile *filsav = gFile;
223  gFile = 0;
224  entry->WriteObject(object);
225  gFile = filsav;
227 // std::cout << "wrote object "<< object->GetName() <<" into message" << std::endl;
228 //
229 // entry->SetReadMode();
230 // entry->Reset();
231 //
232 // entry->InitMap();
233 // TClass* cl= entry->ReadClass();
234 // entry->Reset();
235 // std::cout << "buffer contains class "<< cl << std::endl;
236 // if(cl)
237 // {
238 // std::cout << "classname "<< cl->GetName() << std::endl;
239 //
240 // TObject* ob=entry->ReadObject(cl);
241 // std::cout << "read object "<< ob << std::endl;
242 // if(ob)
243 // std::cout << "read object "<< ob->GetName() << std::endl;
244 // }
246 
247 // do not reset, may need object length information later!
248 // entry->Reset();
249  try
250  {
251  Add(entry);
252  }
253  catch(TGo4RuntimeException& ex)
254  {
255  std::cout << "Buffer queue "<< GetName()<<" is full, dropping new entry "<< entry <<" !!!" << std::endl;
256  delete entry;
257  }
258 
259  }
260 
261 void TGo4BufferQueue::FreeBuffer(TBuffer * buffer)
262 {
263  GO4TRACE((19,"TGo4BufferQueue::FreeBuffer(TBuffer*, Bool_t)", __LINE__, __FILE__));
264  //std::cout << "BBBBBBBBBBBBBBB TGo4BufferQueue::FreeBuffer before taking buffer mutex "<< fxBufferMutex<< std::endl;
266  //std::cout << " bufferlock acquired by bufferqueue: freebuffer"<< std::endl;
267  // does buffer belong to our internal buffers?
268  if (fxBufferList->FindObject(buffer)!=0)
269  {
270  // yes, put it back into the free list
271  // new: we allocate the buffersize back to the initial size to
272  // avoid extended memory consumption:
273  Int_t memsize=buffer->BufferSize();
274  if (memsize>TGo4Socket::fgiBUFINITSIZE)
275  {
276  Realloc(buffer,memsize, TGo4Socket::fgiBUFINITSIZE);
277  }
278  fxFreeList->AddLast(buffer);
279  //std::cout <<"freed buffer"<< buffer <<" of bufferqueue "<< GetName() << std::endl;
280  }
281  else
282  {
283  // no, we delete it to avoid leakage
284  delete buffer;
285  //std::cout <<" Buffer queue FB deleted buffer "<<buffer << std::endl;
286  //std::cout <<"deleted external buffer of bufferqueue "<< GetName() << std::endl;
287  // TGo4Log::Debug(" Buffer Queue : deleted external buffer !!! ");
288 
289  }
290 
291 
292 
293 
294 }
295 
296 
297 void TGo4BufferQueue::Clear(Option_t* opt)
298 {
299  TObject* ob=0;
300  while((ob=Next()) !=0) {
301  //std::cout <<"cleared entry "<<ob<<" of queue "<<GetName() << std::endl;
302  FreeBuffer(dynamic_cast<TBuffer*> (ob) );
303  }
304 }
305 
306 
307 void TGo4BufferQueue::Realloc(TBuffer* buffer, Int_t oldsize, Int_t newsize)
308 {
309  if(buffer==0) return;
310  //std::cout << "TGo4Bufferqueue "<<GetName()<< " Realloc before mainguard"<< std::endl;
311  TGo4LockGuard mainguard;
312  char* memfield = buffer->Buffer();
313  //buffer->Expand(newsize); // is protected! we make it by hand...
314  //Int_t current = buffer->Length(); // cursor position
315  Int_t extraspace=TGo4Socket::fgiBUFEXTRASPACE; // =8, constant within TBuffer
316 // memfield = (char *) TStorage::ReAlloc(memfield,
317 // (newsize + extraspace) * sizeof(char),
318 // (oldsize+ extraspace) * sizeof(char));
319  // this works only for ROOT versions > 3.02/04
320  memfield = TStorage::ReAllocChar(memfield,
321  (newsize+extraspace),
322  (oldsize+extraspace));
323  //std::cout << "Bufferqueue reallocating char from"<<oldsize<< " to " << newsize<< std::endl;
324  buffer->ResetBit(fgiISOWNER);
325 //#if ROOT_VERSION_CODE > ROOT_VERSION(5,23,2)
326 // buffer->SetBuffer(memfield, newsize + extraspace);
327 //#else
328  buffer->SetBuffer(memfield, newsize);
329 //#endif
330  buffer->SetBit(fgiISOWNER);
331  // <- here we avoid the ownership of TBuffer for the internal buffer
332  // (new feature of ROOT versions > 3.02/04)
333  // problem: SetBuffer will delete previous buffer in adopt mode (isowner=true)
334  // which might be at the same location as the new buffer after ReAlloc
335  // ergo SetBuffer would set a buffer which it deleted before itself!
336  buffer->SetBufferOffset(newsize);
337 }
338 
340 {
341  //std::cout <<"nnnnnnnn BufferQueue "<<GetName()<<" new entry before mainguard"<< std::endl;
342  TGo4LockGuard mainguard;
343  TBuffer* buf = new TGo4Buffer(TBuffer::kWrite, TGo4Socket::fgiBUFINITSIZE);
344  //std::cout <<"nnnnnnnn BufferQueue "<<GetName()<<" made new entry "<<buf << std::endl;
345  TNamed* dummy= new TNamed("This is a default buffer filler","GO4 is fun!");
346  TFile *filsav = gFile;
347  gFile = 0;
348  buf->WriteObject(dummy);
349  gFile = filsav;
350  delete dummy;
351  return buf;
352 }
353 
355 {
356  TGo4Buffer* buf= new TGo4Buffer(TBuffer::kWrite);
357  char* field= buf->Buffer() + sizeof(UInt_t);
358  tobuf(field ,val);
359  buf->SetBufferOffset( sizeof(UInt_t)+ sizeof(UInt_t) ); // set length for receiver check
360  buf->SetByteCount(0); // correctly set first longword
361  return buf;
362 }
363 
364 
366 {
367  if(buf==0) return -1;
368  UInt_t len= buf->Length();
369  if(len != (sizeof(UInt_t)+sizeof(UInt_t))) return -2;
370  // note: first length is length of encoded type
371  // second length is always UInt_t
372  char* field=buf->Buffer();
373  char* temp= field + sizeof(UInt_t); // skip length header
374  UInt_t val=0;
375  frombuf(temp, &val);
376  //std::cout <<"DDDDDD DecodeValueBuffer val="<<val << std::endl;
377  return (Int_t) val;
378 }
void Add(TObject *ob)
Definition: TGo4Queue.cxx:67
TMutex * fxBufferMutex
TObject * WaitObjectFromBuffer()
virtual void Clear(Option_t *opt="")
TBuffer * WaitBuffer()
void Realloc(TBuffer *buffer, Int_t oldsize, Int_t newsize)
static const Int_t fgiBUFINITSIZE
Definition: TGo4Socket.h:70
TBuffer * NewEntry()
void AddBuffer(TBuffer *buffer, Bool_t clone=kFALSE)
static Int_t DecodeValueBuffer(TBuffer *buf)
#define TGo4Buffer
Definition: TGo4Buffer.h:27
#define GO4TRACE(X)
Definition: TGo4Log.h:26
TObject * Wait()
Definition: TGo4Queue.cxx:48
static const Int_t fgiISOWNER
static TBuffer * CreateValueBuffer(UInt_t val)
static const Int_t fgiBUFEXTRASPACE
Definition: TGo4Socket.h:73
void FreeBuffer(TBuffer *buffer)
void AddBufferFromObject(TObject *object)
virtual ~TGo4BufferQueue()
static void Debug(const char *text,...)
Definition: TGo4Log.cxx:270
TObject * Next()
Definition: TGo4Queue.cxx:61