]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - HLT/BASE/AliHLTOUT.cxx
bugfix: correct range of DDL for specified detector
[u/mrichter/AliRoot.git] / HLT / BASE / AliHLTOUT.cxx
index 26826b157a3e80375e337519c23635f6f3c90209..8357ae465678fd0c48eee6b3b4bddc8541218a6e 100644 (file)
@@ -1,35 +1,38 @@
 // $Id$
 
-/**************************************************************************
- * This file is property of and copyright by the ALICE HLT Project        * 
- * ALICE Experiment at CERN, All rights reserved.                         *
- *                                                                        *
- * Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
- *                  for The ALICE HLT Project.                            *
- *                                                                        *
- * Permission to use, copy, modify and distribute this software and its   *
- * documentation strictly for non-commercial purposes is hereby granted   *
- * without fee, provided that the above copyright notice appears in all   *
- * copies and that both the copyright notice and this permission notice   *
- * appear in the supporting documentation. The authors make no claims     *
- * about the suitability of this software for any purpose. It is          *
- * provided "as is" without express or implied warranty.                  *
- **************************************************************************/
-
-/** @file   AliHLTOUT.cxx
-    @author Matthias Richter
-    @date   
-    @brief  The control class for HLTOUT data.                            */
-
-// see header file for class documentation
-// or
-// refer to README to build package
-// or
-// visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
+//**************************************************************************
+//* This file is property of and copyright by the ALICE HLT Project        * 
+//* ALICE Experiment at CERN, All rights reserved.                         *
+//*                                                                        *
+//* Primary Authors: Matthias Richter <Matthias.Richter@ift.uib.no>        *
+//*                  for The ALICE HLT Project.                            *
+//*                                                                        *
+//* Permission to use, copy, modify and distribute this software and its   *
+//* documentation strictly for non-commercial purposes is hereby granted   *
+//* without fee, provided that the above copyright notice appears in all   *
+//* copies and that both the copyright notice and this permission notice   *
+//* appear in the supporting documentation. The authors make no claims     *
+//* about the suitability of this software for any purpose. It is          *
+//* provided "as is" without express or implied warranty.                  *
+//**************************************************************************
+
+/// @file   AliHLTOUT.cxx
+/// @author Matthias Richter
+/// @date   
+/// @brief  The control class for HLTOUT data.
+///
 
 #include <cerrno>
 #include <cassert>
 #include "AliHLTOUT.h"
+#include "AliHLTMessage.h"
+#include "AliHLTMisc.h"
+#include "TSystem.h"
+#include "TClass.h"
+#include "TROOT.h"
+#include <sstream>
+#include <iomanip>
+using namespace std;
 
 /** ROOT macro for the implementation of ROOT specific class methods */
 ClassImp(AliHLTOUT)
@@ -39,29 +42,49 @@ AliHLTOUT::AliHLTOUT()
   fSearchDataType(kAliHLTVoidDataType),
   fSearchSpecification(kAliHLTVoidDataSpec),
   fSearchHandlerType(AliHLTModuleAgent::kUnknownOutput),
-  fFlags(0),
+  fFlags(kSkipProcessed),
   fBlockDescList(),
-  fCurrent(fBlockDescList.begin()),
+  fCurrent(0),
   fpBuffer(NULL),
   fDataHandlers(),
-  fbVerbose(true)
+  fbVerbose(false),
+  fLog()
+  , fpDataObject(NULL)
+  , fpObjectBuffer(NULL)
+  , fObjectBufferSize(0)
+  , fCurrentEventId(kAliHLTVoidEventID)
 {
+  // constructor
+  // 
+  // The control class for HLTOUT data
   // see header file for class documentation
-  // or
-  // refer to README to build package
-  // or
-  // visit http://web.ift.uib.no/~kjeks/doc/alice-hlt
+  // author Matthias Richter
 }
 
 AliHLTOUT::~AliHLTOUT()
 {
-  // see header file for class documentation
+  // destructor
+  if (CheckStatusFlag(kIsSubCollection)) {
+    fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "~AliHLTOUT" , __FILE__ , __LINE__ , "severe internal error: collection has not been released, potential crash due to invalid pointer");
+  }
+
+  if (fpDataObject) {
+    fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "data object has not been released, potential memory leak");
+  }
+  fpDataObject=NULL;
 }
+AliHLTOUT* AliHLTOUT::fgGlobalInstance=NULL;
 
 int AliHLTOUT::Init()
 {
   // see header file for class documentation
   int iResult=0;
+
+  // ignore if already initialized
+  if (fBlockDescList.size()>0) {
+    return 0;
+  }
+
   SetStatusFlag(kCollecting);
   if ((iResult=GenerateIndex())>=0) {
     if ((iResult=InitHandlers())>=0) {
@@ -73,41 +96,47 @@ int AliHLTOUT::Init()
 
 int AliHLTOUT::GetNofDataBlocks()
 {
-  // see header file for class documentation
+  // get number of data blocks
   return fBlockDescList.size();
 }
 
 int AliHLTOUT::SelectFirstDataBlock(AliHLTComponentDataType dt, AliHLTUInt32_t spec,
-                                   AliHLTModuleAgent::AliHLTOUTHandlerType handlerType)
+                                   AliHLTModuleAgent::AliHLTOUTHandlerType handlerType,
+                                   bool skipProcessed)
 {
-  // see header file for class documentation
-  if (CheckStatusFlag(kLocked)) return -EPERM;
-  fCurrent=fBlockDescList.begin();
+  // select the first data block according to data type, specification and
+  // handler type
+  fCurrent=0;
   fSearchDataType=dt;
   fSearchSpecification=spec;
   fSearchHandlerType=handlerType;
+  if (skipProcessed) SetStatusFlag(kSkipProcessed);
+  else ClearStatusFlag(kSkipProcessed);
   return FindAndSelectDataBlock();
 }
 
 int AliHLTOUT::SelectNextDataBlock()
 {
-  // see header file for class documentation
-  if (CheckStatusFlag(kLocked)) return -EPERM;
-  if (fCurrent==fBlockDescList.end()) return -ENOENT;
+  // select next data block according to selection criteria specified
+  // for SelectFirstDataBlock
+  if (fCurrent>=fBlockDescList.size()) return -ENOENT;
   fCurrent++;
   return FindAndSelectDataBlock();
 }
 
 int AliHLTOUT::FindAndSelectDataBlock()
 {
-  // see header file for class documentation
+  // Select data block according to data type and specification, internal function
+  // invoked by SelectFirstDataBlock/SelectNextDataBlock
   if (CheckStatusFlag(kLocked)) return -EPERM;
   int iResult=-ENOENT;
-  while (fCurrent!=fBlockDescList.end() && iResult==-ENOENT) {
-    if ((*fCurrent)==fSearchDataType &&
-       (fSearchSpecification==kAliHLTVoidDataSpec || (*fCurrent)==fSearchSpecification) &&
-       (fSearchHandlerType==AliHLTModuleAgent::kUnknownOutput || FindHandlerDesc(fCurrent->GetIndex())==fSearchHandlerType)) {
-      iResult=fCurrent->GetIndex();
+  while (fCurrent<fBlockDescList.size() && iResult==-ENOENT) {
+    if (fBlockDescList[fCurrent]==fSearchDataType &&
+       (fSearchSpecification==kAliHLTVoidDataSpec || fBlockDescList[fCurrent]==fSearchSpecification) &&
+       (fSearchHandlerType==AliHLTModuleAgent::kUnknownOutput || FindHandlerDesc(fCurrent)==fSearchHandlerType) &&
+       (!CheckStatusFlag(kBlockSelection) || fBlockDescList[fCurrent].IsSelected()) &&
+       (!CheckStatusFlag(kSkipProcessed) || !fBlockDescList[fCurrent].IsProcessed())) {
+      iResult=fBlockDescList[fCurrent].GetIndex();
       // TODO: check the byte order on the current system and the byte order of the
       // data block, print warning when mismatch and user did not check
       //AliHLTOUTByteOrder blockBO=CheckByteOrder();
@@ -133,46 +162,63 @@ int AliHLTOUT::FindAndSelectDataBlock()
 
 int AliHLTOUT::GetDataBlockDescription(AliHLTComponentDataType& dt, AliHLTUInt32_t& spec)
 {
-  // see header file for class documentation
+  // fill data type and specification
   int iResult=-ENOENT;
-  if (fCurrent!=fBlockDescList.end()) {
+  if (fCurrent<fBlockDescList.size()) {
     iResult=0;
-    dt=(*fCurrent);
-    spec=(*fCurrent);
+    dt=fBlockDescList[fCurrent];
+    spec=fBlockDescList[fCurrent];
   }
   return iResult;
 }
 
 const AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::GetDataBlockHandlerDesc()
 {
-  // see header file for class documentation
-  return FindHandlerDesc(GetDataBlockIndex());
+  // Get handler descriptor of the selected data block.
+  return FindHandlerDesc(fCurrent);
 }
 
 AliHLTModuleAgent::AliHLTOUTHandlerType AliHLTOUT::GetDataBlockHandlerType()
 {
-  // see header file for class documentation
-  AliHLTModuleAgent::AliHLTOUTHandlerDesc desc=FindHandlerDesc(GetDataBlockIndex());
+  // Get handler type of the selected data block.
+  AliHLTModuleAgent::AliHLTOUTHandlerDesc desc=FindHandlerDesc(fCurrent);
   AliHLTModuleAgent::AliHLTOUTHandlerType type=desc;
   return type;
 }
 
 AliHLTUInt32_t AliHLTOUT::GetDataBlockIndex()
 {
-  // see header file for class documentation
-  if (fCurrent==fBlockDescList.end()) return AliHLTOUTInvalidIndex;
-  return fCurrent->GetIndex();
+  // Get the index of the current data block.
+  if (fCurrent>=fBlockDescList.size()) return AliHLTOUTInvalidIndex;
+  return fBlockDescList[fCurrent].GetIndex();
+}
+
+int AliHLTOUT::GetDataBuffer(AliHLTComponentBlockData& desc)
+{
+  // fill block data descriptor and select the current data buffer
+  // buffer has to be released using ReleaseDataBuffer
+  int iResult=-ENOENT;
+  if (fCurrent<fBlockDescList.size()) {
+    AliHLTComponent::FillBlockData(desc);
+    if ((iResult=fBlockDescList[fCurrent].GetDataBuffer(fpBuffer, desc.fSize))>=0) {
+      desc.fPtr=const_cast<void*>(reinterpret_cast<const void*>(fpBuffer));
+      desc.fDataType=fBlockDescList[fCurrent];
+      desc.fSpecification=fBlockDescList[fCurrent];
+    }
+  }
+  return iResult;
 }
 
 int AliHLTOUT::GetDataBuffer(const AliHLTUInt8_t* &pBuffer, AliHLTUInt32_t& size)
 {
-  // see header file for class documentation
+  // select and return the current data buffer
+  // buffer has to be released using ReleaseDataBuffer
   int iResult=-ENOENT;
   pBuffer=NULL;
   size=0;
-  if (fCurrent!=fBlockDescList.end()) {
-    if ((iResult=GetDataBuffer(fCurrent->GetIndex(), pBuffer, size))>=0) {
-      fpBuffer=pBuffer;
+  if (fCurrent<fBlockDescList.size()) {
+    if ((iResult=fBlockDescList[fCurrent].GetDataBuffer(fpBuffer, size))>=0) {
+      pBuffer=fpBuffer;
     }
   }
   return iResult;  
@@ -180,42 +226,42 @@ int AliHLTOUT::GetDataBuffer(const AliHLTUInt8_t* &pBuffer, AliHLTUInt32_t& size
 
 int AliHLTOUT::ReleaseDataBuffer(const AliHLTUInt8_t* pBuffer)
 {
-  // see header file for class documentation
+  // release data buffer, previously returned by GetDataBuffer
   int iResult=0;
   if (pBuffer==fpBuffer) {
     fpBuffer=NULL;
   } else {
-    HLTWarning("buffer %p does not match the provided one %p", pBuffer, fpBuffer);
+    fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "ReleaseDataBuffer" , __FILE__ , __LINE__ , "buffer %p does not match the provided one %p", pBuffer, fpBuffer);
   }
   return iResult;  
 }
 
 AliHLTModuleAgent* AliHLTOUT::GetAgent()
 {
-  // see header file for class documentation
+  // get module agent of the selected data block
   AliHLTModuleAgent* pAgent=NULL;
-  pAgent=FindHandlerDesc(GetDataBlockIndex());
+  pAgent=FindHandlerDesc(fCurrent);
   return pAgent;
 }
 
 AliHLTOUTHandler* AliHLTOUT::GetHandler()
 {
-  // see header file for class documentation
+  // get HLTOUT handler of the selected data block
   AliHLTOUTHandler* pHandler=NULL;
-  pHandler=FindHandlerDesc(GetDataBlockIndex());
+  pHandler=FindHandlerDesc(fCurrent);
   return pHandler;
 }
 
 int AliHLTOUT::WriteESD(const AliHLTUInt8_t* /*pBuffer*/, AliHLTUInt32_t /*size*/, AliHLTComponentDataType /*dt*/, AliESDEvent* /*tgtesd*/) const
 {
-  // see header file for class documentation
-  HLTWarning("method not implemented in base class");
+  // default function, child must overload
+  fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "WriteESD" , __FILE__ , __LINE__ , "method not implemented in base class");
   return -ENOSYS;
 }
 
 int AliHLTOUT::AddBlockDescriptor(const AliHLTOUTBlockDescriptor desc)
 {
-  // see header file for class documentation
+  // add new block descriptor
   if (!CheckStatusFlag(kCollecting)) return -EPERM;
   int iResult=0;
   fBlockDescList.push_back(desc);
@@ -224,10 +270,11 @@ int AliHLTOUT::AddBlockDescriptor(const AliHLTOUTBlockDescriptor desc)
 
 AliHLTOUT::AliHLTOUTByteOrder AliHLTOUT::CheckByteOrder()
 {
-  // see header file for class documentation
-  if (fCurrent!=fBlockDescList.end()) {
+  // check the byte order of the current data block
+  // NOTE: this functionality has not been tested and development was hardly finished
+  if (fCurrent<fBlockDescList.size()) {
     SetStatusFlag(kByteOrderChecked);
-    AliHLTOUT::AliHLTOUTByteOrder order=CheckBlockByteOrder((*fCurrent).GetIndex());
+    AliHLTOUT::AliHLTOUTByteOrder order=CheckBlockByteOrder(fBlockDescList[fCurrent].GetIndex());
     return order;
   }
   return kInvalidByteOrder;
@@ -235,10 +282,11 @@ AliHLTOUT::AliHLTOUTByteOrder AliHLTOUT::CheckByteOrder()
 
 int AliHLTOUT::CheckAlignment(AliHLTOUT::AliHLTOUTDataType type)
 {
-  // see header file for class documentation
-  if (fCurrent!=fBlockDescList.end()) {
+  // check alignment of the current data block
+  // NOTE: this functionality has not been tested and development was hardly finished
+  if (fCurrent<fBlockDescList.size()) {
     SetStatusFlag(kAlignmentChecked);
-    int alignment=CheckBlockAlignment((*fCurrent).GetIndex(), type);
+    int alignment=CheckBlockAlignment(fBlockDescList[fCurrent].GetIndex(), type);
     return alignment;
   }
   return -ENOENT;
@@ -246,7 +294,7 @@ int AliHLTOUT::CheckAlignment(AliHLTOUT::AliHLTOUTDataType type)
 
 int AliHLTOUT::InitHandlers()
 {
-  // see header file for class documentation
+  // init handlers for all registered blocks
   int iResult=0;
   AliHLTOUTIndexList remnants;
   int iCount=0;
@@ -256,28 +304,42 @@ int AliHLTOUT::InitHandlers()
     AliHLTComponentDataType dt=kAliHLTVoidDataType;
     AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
     if (GetDataBlockDescription(dt, spec)<0) break;
+    bool bHaveHandler=false;
     for (AliHLTModuleAgent* pAgent=AliHLTModuleAgent::GetFirstAgent(); pAgent && iResult>=0; pAgent=AliHLTModuleAgent::GetNextAgent()) {
       AliHLTModuleAgent::AliHLTOUTHandlerDesc handlerDesc;
       if (pAgent->GetHandlerDescription(dt, spec, handlerDesc)>0) {
        AliHLTOUTHandlerListEntry entry(pAgent->GetOutputHandler(dt, spec), handlerDesc, pAgent, GetDataBlockIndex());
        InsertHandler(fDataHandlers, entry);
        remnants.pop_back();
+       bHaveHandler=true;
+       if (fbVerbose) {
+         stringstream sout;
+         sout << "adding handler for block " << AliHLTComponent::DataType2Text(dt).c_str()
+              << " 0x" << setfill('0') << setw(8) << hex << spec;
+         cout << sout.str() << endl;
+       }
        break;
       }
     }
+    if (!bHaveHandler && (dt==kAliHLTDataTypeESDObject || dt==kAliHLTDataTypeESDTree)) {
+      // ESDs are handled by the framework
+      remnants.pop_back();
+    }
   }
 
   // warning if some of the data blocks are not selected by the kAliHLTAnyDataType
   // criterion
   if (GetNofDataBlocks()>iCount) {
-    HLTWarning("incomplete data type in %d out of %d data block(s)", GetNofDataBlocks()-iCount, iCount);
+    fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "InitHandlers" , __FILE__ , __LINE__ , "incomplete data type in %d out of %d data block(s)", GetNofDataBlocks()-iCount, GetNofDataBlocks());
   }
 
   // warning if handler not found
   if (remnants.size()>0) {
-    HLTWarning("no handlers found for %d data blocks out of %d", remnants.size(), iCount);
+    fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "InitHandlers" , __FILE__ , __LINE__ , "no handlers found for %d data blocks out of %d", remnants.size(), iCount);
     AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
-    for (AliHLTOUTIndexList::iterator element=remnants.begin(); element!=remnants.end(); element++) {
+    for (AliHLTOUTIndexList::iterator element=remnants.begin();
+        element!=remnants.end() && block!=fBlockDescList.end();
+        element++) {
       for (int trials=0; trials<2; trials++) {
        do {
          // we start searching the index from the current position in the block list
@@ -289,22 +351,22 @@ int AliHLTOUT::InitHandlers()
        }
       }
       assert(block!=fBlockDescList.end());
-      if (block!=fBlockDescList.end()) {
-       HLTDebug("   %s", AliHLTComponent::DataType2Text((AliHLTComponentDataType)*block).c_str());
-      }
     }
   }
+
+  if (fbVerbose) Print();
+
   return iResult;
 }
 
 int AliHLTOUT::InsertHandler(AliHLTOUTHandlerListEntryVector& list, const AliHLTOUTHandlerListEntry &entry)
 {
-  // see header file for class documentation
+  // insert handler into list, called from child implementations
   int iResult=0;
   AliHLTOUTHandlerListEntryVector::iterator element=list.begin();
-  while (element!=list.end()) {
+  for (; element!=list.end();
+        element++) {
     if (entry==(*element)) break;
-    element++;
   }
   if (element==list.end()) {
     list.push_back(entry);
@@ -314,16 +376,83 @@ int AliHLTOUT::InsertHandler(AliHLTOUTHandlerListEntryVector& list, const AliHLT
   return iResult;
 }
 
-const AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::FindHandlerDesc(AliHLTUInt32_t blockIndex)
+int AliHLTOUT::FillHandlerList(AliHLTOUTHandlerListEntryVector& list, AliHLTModuleAgent::AliHLTOUTHandlerType handlerType)
 {
-  // see header file for class documentation
-  AliHLTOUTHandlerListEntryVector::iterator element=fDataHandlers.begin();
-  while (element!=fDataHandlers.end()) {
-    if (element->HasIndex(blockIndex)) {
-      return *element;
+  // fill a list according to specified handler type
+  int iResult=0;
+  for (iResult=SelectFirstDataBlock(kAliHLTAnyDataType, kAliHLTVoidDataSpec, handlerType);
+       iResult>=0;
+       iResult=SelectNextDataBlock()) {
+    AliHLTComponentDataType dt=kAliHLTVoidDataType;
+    AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
+    GetDataBlockDescription(dt, spec);
+    AliHLTOUTHandler* pHandler=GetHandler();
+    if (!pHandler) {
+      fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "FillHandlerList" , __FILE__ , __LINE__ , 
+                        "missing HLTOUT handler for block of type kChain: agent %s, data type %s, specification %#x, ... skipping data block",
+                        GetAgent()?GetAgent()->GetModuleId():"invalid",
+                        AliHLTComponent::DataType2Text(dt).c_str(), spec);
+    } else {
+      InsertHandler(list, GetDataBlockHandlerDesc());
+    }
+  }
+  // TODO: the return value of SelectFirst/NextDataBlock must be
+  // changed in order to avoid this check
+  if (iResult==-ENOENT) iResult=0;
+
+  return iResult;
+}
+
+int AliHLTOUT::RemoveEmptyDuplicateHandlers(AliHLTOUTHandlerListEntryVector& list)
+{
+  // remove empty handlers from list
+  int iResult=0;
+  AliHLTOUTHandlerListEntryVector::iterator element=list.begin();
+  while (element!=list.end()) {
+    if (element->IsEmpty()) {
+      AliHLTOUTHandler* pHandler=*element;
+      AliHLTModuleAgent* pAgent=*element;
+      AliHLTModuleAgent::AliHLTOUTHandlerDesc desc=*element;
+      if (FindHandler(list, desc)>=0) {
+       element=list.erase(element);
+       if (pAgent) {
+         pAgent->DeleteOutputHandler(pHandler);
+       }
+       // we are already at the next element
+       continue;
+      }
     }
     element++;
   }
+  return iResult;
+}
+
+int AliHLTOUT::FindHandler(AliHLTOUTHandlerListEntryVector& list, const AliHLTModuleAgent::AliHLTOUTHandlerDesc desc)
+{
+  // find handler according to descriptor
+  for (int i=0; i<(int)list.size(); i++) {
+    if (list[i]==desc) return i;
+  }
+  return -ENOENT;
+}
+
+int AliHLTOUT::InvalidateBlocks(AliHLTOUTHandlerListEntryVector& list)
+{
+  // invalidate all handlers in a list
+  for (AliHLTOUTHandlerListEntryVector::iterator element=list.begin();
+        element!=list.end();
+        element++) {
+    element->InvalidateBlocks();
+  }
+  return 0;
+}
+
+const AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::FindHandlerDesc(AliHLTUInt32_t blockIndex)
+{
+  // get handler description
+  if (blockIndex<fBlockDescList.size()) {
+    return fBlockDescList[blockIndex].GetHandlerDesc();
+  }
   return const_cast<AliHLTOUT::AliHLTOUTHandlerListEntry&>(AliHLTOUT::AliHLTOUTHandlerListEntry::fgkVoidHandlerListEntry);
 }
 
@@ -334,7 +463,7 @@ AliHLTOUT::AliHLTOUTHandlerListEntry::AliHLTOUTHandlerListEntry()
   fpAgent(NULL),
   fBlocks()
 {
-  // see header file for class documentation
+  // default constructor
 }
 
 AliHLTOUT::AliHLTOUTHandlerListEntry::AliHLTOUTHandlerListEntry(AliHLTOUTHandler* pHandler, 
@@ -347,7 +476,7 @@ AliHLTOUT::AliHLTOUTHandlerListEntry::AliHLTOUTHandlerListEntry(AliHLTOUTHandler
   fpAgent(pAgent),
   fBlocks()
 {
-  // see header file for class documentation
+  // constructor
   *fpHandlerDesc=handlerDesc;
   fBlocks.push_back(index);
 }
@@ -359,21 +488,22 @@ AliHLTOUT::AliHLTOUTHandlerListEntry::AliHLTOUTHandlerListEntry(const AliHLTOUTH
   fpAgent(src.fpAgent),
   fBlocks()
 {
-  // see header file for class documentation
+  // copy constructor
   *fpHandlerDesc=*src.fpHandlerDesc;
   fBlocks.assign(src.fBlocks.begin(), src.fBlocks.end());
 }
 
 AliHLTOUT::AliHLTOUTHandlerListEntry::~AliHLTOUTHandlerListEntry()
 {
-  // see header file for class documentation
+  // destructor
   if (fpHandlerDesc) delete fpHandlerDesc;
   fpHandlerDesc=NULL;
 }
 
 AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::AliHLTOUTHandlerListEntry::operator=(const AliHLTOUTHandlerListEntry& src)
 {
-  // see header file for class documentation
+  // assignment operator
+  if (this==&src) return *this;  
   fpHandler=src.fpHandler;
   if (src.fpHandlerDesc)
     *fpHandlerDesc=*src.fpHandlerDesc;
@@ -384,13 +514,13 @@ AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::AliHLTOUTHandlerListEntry::oper
 
 AliHLTUInt32_t AliHLTOUT::AliHLTOUTHandlerListEntry::operator[](int i) const
 {
-  // see header file for class documentation
+  // access operator
   return (int)fBlocks.size()>i?fBlocks[i]:AliHLTOUTInvalidIndex;
 }
 
 bool AliHLTOUT::AliHLTOUTHandlerListEntry::operator==(const AliHLTOUTHandlerListEntry& entry) const
 {
-  // see header file for class documentation
+  // comparison operator
   if (entry.fpHandler!=fpHandler || fpHandler==NULL) return false;
   assert(entry.fpAgent==fpAgent);
   if (entry.fpAgent!=fpAgent) return false;
@@ -399,14 +529,21 @@ bool AliHLTOUT::AliHLTOUTHandlerListEntry::operator==(const AliHLTOUTHandlerList
 
 bool AliHLTOUT::AliHLTOUTHandlerListEntry::operator==(const AliHLTModuleAgent::AliHLTOUTHandlerType handlerType) const
 {
-  // see header file for class documentation
+  // comparison operator
   if (!fpHandlerDesc) return false;
   return *fpHandlerDesc==handlerType;
 }
 
+bool AliHLTOUT::AliHLTOUTHandlerListEntry::operator==(const AliHLTModuleAgent::AliHLTOUTHandlerDesc desc) const
+{
+  // comparison operator
+  if (!fpHandlerDesc) return false;
+  return *fpHandlerDesc==desc;
+}
+
 void AliHLTOUT::AliHLTOUTHandlerListEntry::AddIndex(AliHLTOUT::AliHLTOUTHandlerListEntry &desc)
 {
-  // see header file for class documentation
+  // add block index, a handler can serve multiple blocks
   AliHLTOUTIndexList::iterator element;
   for (element=desc.fBlocks.begin(); element!=desc.fBlocks.end(); element++) {
     AddIndex(*element);
@@ -415,16 +552,16 @@ void AliHLTOUT::AliHLTOUTHandlerListEntry::AddIndex(AliHLTOUT::AliHLTOUTHandlerL
 
 void AliHLTOUT::AliHLTOUTHandlerListEntry::AddIndex(AliHLTUInt32_t index)
 {
-  // see header file for class documentation
+  // add block index, a handler can serve multiple blocks
   fBlocks.push_back(index);
 }
 
-bool AliHLTOUT::AliHLTOUTHandlerListEntry::HasIndex(AliHLTUInt32_t index)
+bool AliHLTOUT::AliHLTOUTHandlerListEntry::HasIndex(AliHLTUInt32_t index) const
 {
-  // see header file for class documentation
+  // check if handler serves the specified block
   AliHLTOUTIndexList::iterator element;
-  for (element=fBlocks.begin(); element!=fBlocks.end(); element++) {
-    if (*element==index) return true;
+  for (unsigned int i=0; i<fBlocks.size(); i++) {
+    if (fBlocks[i]==index) return true;
   }
   return false;
 }
@@ -433,7 +570,7 @@ const AliHLTOUT::AliHLTOUTHandlerListEntry AliHLTOUT::AliHLTOUTHandlerListEntry:
 
 AliHLTUInt64_t AliHLTOUT::ByteSwap64(AliHLTUInt64_t src)
 {
-  // see header file for class documentation
+  // swap a 64 bit number
   return ((src & 0xFFULL) << 56) | 
     ((src & 0xFF00ULL) << 40) | 
     ((src & 0xFF0000ULL) << 24) | 
@@ -446,9 +583,389 @@ AliHLTUInt64_t AliHLTOUT::ByteSwap64(AliHLTUInt64_t src)
 
 AliHLTUInt32_t AliHLTOUT::ByteSwap32(AliHLTUInt32_t src)
 {
-  // see header file for class documentation
+  // swap a 32 bit number
   return ((src & 0xFFULL) << 24) | 
     ((src & 0xFF00ULL) << 8) | 
     ((src & 0xFF0000ULL) >> 8) | 
     ((src & 0xFF000000ULL) >> 24);
 }
+
+AliHLTOUT* AliHLTOUT::New(AliRawReader* pRawReader)
+{
+  // transparently create HLTOUT implementation for AliRawReader
+  AliHLTOUT* instance=AliHLTMisc::LoadInstance((AliHLTOUT*)0, "AliHLTOUTRawReader", "libHLTrec.so");
+  if (instance) {
+    instance->SetParam(pRawReader);
+  }
+  return instance;
+}
+
+AliHLTOUT* AliHLTOUT::New(TTree* pDigitTree, int event)
+{
+  // transparently create HLTOUT implementation for digit tree
+  AliHLTOUT* instance=AliHLTMisc::LoadInstance((AliHLTOUT*)0, "AliHLTOUTDigitReader", "libHLTrec.so");
+  if (instance) {
+    instance->SetParam(pDigitTree, event);
+  }
+  return instance;
+}
+
+AliHLTOUT* AliHLTOUT::New(const char* filename, int event)
+{
+  // transparently create HLTOUT implementation for raw file
+  AliHLTOUT* instance=AliHLTMisc::LoadInstance((AliHLTOUT*)0, "AliHLTOUTDigitReader", "libHLTrec.so");
+  if (instance) {
+    instance->SetParam(filename, event);
+  }
+  return instance;
+}
+
+void AliHLTOUT::Delete(AliHLTOUT* pInstance)
+{
+  // delete the HLTOUT instance
+  // check if the library is still there in order to have the
+  // destructor available
+
+  if (!pInstance) return;
+  if (pInstance==fgGlobalInstance) return;
+
+  TClass* pCl1=TClass::GetClass("AliHLTOUTRawReader");
+  TClass* pCl2=TClass::GetClass("AliHLTOUTDigitReader");
+  if (!pCl1 && !pCl2) {
+    AliHLTLogging log;
+    log.Logging(kHLTLogError, "AliHLTOUT::Delete", "HLTOUT handling", "potential memory leak: libHLTrec library not available, skipping destruction %p", pInstance);    
+    return;
+  }
+
+  delete pInstance;  
+}
+
+void AliHLTOUT::SetParam(AliRawReader* /*pRawReader*/)
+{
+  // see header file for class documentation
+  // default implementation, we should never get here
+  // this function can only be called from the class itsself and
+  // is intended to be used with the New functions. If we get into
+  // the default implementation there is a class mismatch.
+  assert(0);
+  fLog.LoggingVarargs(kHLTLogFatal, "AliHLTOUT", "SetParam" , __FILE__ , __LINE__ , "severe internal error: class mismatch");
+}
+
+void AliHLTOUT::SetParam(TTree* /*pDigitTree*/, int /*event*/)
+{
+  // see header file for class documentation
+  // default implementation, we should never get here
+  // this function can only be called from the class itsself and
+  // is intended to be used with the New functions. If we get into
+  // the default implementation there is a class mismatch.
+  assert(0);
+  fLog.LoggingVarargs(kHLTLogFatal, "AliHLTOUT", "SetParam" , __FILE__ , __LINE__ , "severe internal error: class mismatch");
+}
+
+void AliHLTOUT::SetParam(const char* /*filename*/, int /*event*/)
+{
+  // see header file for class documentation
+  // default implementation, we should never get here
+  // this function can only be called from the class itsself and
+  // is intended to be used with the New functions. If we get into
+  // the default implementation there is a class mismatch.
+  assert(0);
+  fLog.LoggingVarargs(kHLTLogFatal, "AliHLTOUT", "SetParam" , __FILE__ , __LINE__ , "severe internal error: class mismatch");
+}
+
+int AliHLTOUT::SelectDataBlock()
+{
+  // mark the current data block for processing
+  int iResult=0;
+  if (fCurrent>=fBlockDescList.size()) return 0;
+  fBlockDescList[fCurrent].Select(true);
+  EnableBlockSelection();
+  return iResult;
+}
+
+int AliHLTOUT::SelectDataBlocks(const AliHLTOUTHandlerListEntry* pHandlerEntry)
+{
+  // mark all data blocks served by specified handler for processing
+  int iResult=0;
+  if (!pHandlerEntry) return 0;
+
+  AliHLTModuleAgent* pAgent=*pHandlerEntry;
+  AliHLTLogging log;
+  log.Logging(kHLTLogDebug, "AliHLTOUT::SelectDataBlocks", "HLTOUT handling", "selecting blocks for handler %s", pAgent->GetModuleId());
+  AliHLTOUTBlockDescriptorVector::iterator element;
+  for (AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
+       block!=fBlockDescList.end();
+       block++) {
+    if (block->GetHandlerDesc()==*pHandlerEntry && pHandlerEntry->HasIndex(block->GetIndex())) {
+      block->Select(true);
+      log.Logging(kHLTLogDebug, "AliHLTOUT::SelectDataBlocks", "HLTOUT handling", "   select block %s", AliHLTComponent::DataType2Text(*block).c_str());
+    } else {
+      log.Logging(kHLTLogDebug, "AliHLTOUT::SelectDataBlocks", "HLTOUT handling", "   skip block %s", AliHLTComponent::DataType2Text(*block).c_str());
+      block->Select(false);
+    }
+  }
+  EnableBlockSelection();
+
+  // Matthias 2009-07-03 bugfix: the fCurrent position was not reset at that
+  // place. Also I think the data type and specification must be set in order
+  // to make SelectFirst/NextDataBlock working on the selected collection
+  // of data blocks
+  AliHLTModuleAgent::AliHLTOUTHandlerDesc pHandlerDesc=*pHandlerEntry; 
+  fSearchDataType=pHandlerDesc;
+  fSearchSpecification=kAliHLTVoidDataSpec;
+  fSearchHandlerType=pHandlerDesc;
+  fCurrent=0;
+  
+  return iResult;
+}
+
+int AliHLTOUT::EnableBlockSelection()
+{
+  // enable block selection, in this mode only the blocks marked for
+  // processing can be accessed
+  SetStatusFlag(kBlockSelection);
+  return 0;
+}
+
+int AliHLTOUT::DisableBlockSelection()
+{
+  // disable block selection
+  ClearStatusFlag(kBlockSelection);
+  return 0;
+}
+
+int AliHLTOUT::ResetBlockSelection()
+{
+  // reset the 'selected' flag for all blocks
+  for (AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
+       block!=fBlockDescList.end();
+       block++) {
+    block->Select(false);
+  }
+  return 0;
+}
+
+int AliHLTOUT::MarkDataBlockProcessed()
+{
+  // mark the current data block as 'processed'
+  int iResult=0;
+  if (fCurrent>=fBlockDescList.size()) return 0;
+  fBlockDescList[fCurrent].MarkProcessed();
+  return iResult;
+}
+
+int AliHLTOUT::MarkDataBlocksProcessed(const AliHLTOUTHandlerListEntry* pHandlerDesc)
+{
+  // mark all data blocks served by handler as processed
+  int iResult=0;
+  if (!pHandlerDesc) return 0;
+
+  AliHLTOUTBlockDescriptorVector::iterator element;
+  for (AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
+       block!=fBlockDescList.end();
+       block++) {
+    if (block->GetHandlerDesc()==*pHandlerDesc && pHandlerDesc->HasIndex(block->GetIndex()))
+      block->MarkProcessed();
+  }
+  
+  return iResult;
+}
+
+int AliHLTOUT::AddSubCollection(AliHLTOUT* pCollection)
+{
+  // add a sub-collection to the HLTOUT instance
+  // all blocks of the sub-collection are accessed transparently through the master instance
+  int iResult=0;
+  if (!pCollection) return 0;
+
+  SetStatusFlag(kCollecting);  
+  int index=-1;
+  for (index=pCollection->SelectFirstDataBlock();
+       index>=0;
+       index=pCollection->SelectNextDataBlock()) {
+    AliHLTComponentDataType dt=kAliHLTVoidDataType;
+    AliHLTUInt32_t spec=kAliHLTVoidDataSpec;
+    pCollection->GetDataBlockDescription(dt, spec);  
+    AliHLTOUTBlockDescriptor desc(dt, spec, index, pCollection);
+    AddBlockDescriptor(desc);
+    iResult++;
+  }
+  if (iResult>0) {
+    if (CheckStatusFlag(kIsSubCollection)) {
+      fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "AddSubCollection" , __FILE__ , __LINE__ , "HLTOUT object %p has already been added as sub-collection", pCollection);
+    } else {
+      pCollection->SetStatusFlag(kIsSubCollection);
+    }
+  }
+  ClearStatusFlag(kCollecting);  
+
+  return iResult;
+}
+
+int AliHLTOUT::ReleaseSubCollection(AliHLTOUT* pCollection)
+{
+  // release a sub-collection
+  int iResult=0;
+  if (!pCollection) return 0;
+
+  AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
+  while (block!=fBlockDescList.end()) {
+    if ((*block)==pCollection) {
+      block=fBlockDescList.erase(block);
+      continue;
+    }
+    block++;
+  }
+  pCollection->ClearStatusFlag(kIsSubCollection);
+
+  return iResult;
+}
+
+int AliHLTOUT::Reset()
+{
+  // reset HLTOUT instance
+  // clears all blocks and handler descriptions
+  int iResult=0;
+  AliHLTOUTPVector subCollections;
+  AliHLTOUTBlockDescriptorVector::iterator block=fBlockDescList.begin();
+  while (block!=fBlockDescList.end()) {
+    if (!((*block)==this)) {
+      AliHLTOUTPVector::iterator collection=subCollections.begin();
+      for (; collection!=subCollections.end(); collection++)
+       if((*block)==*collection) break;
+      if (collection==subCollections.end())
+       subCollections.push_back(block->GetCollection());
+    }
+    block=fBlockDescList.erase(block);
+  }
+
+  for (AliHLTOUTPVector::iterator collection=subCollections.begin(); 
+       collection!=subCollections.end(); collection++) {
+    (*collection)->Reset();
+    (*collection)->ClearStatusFlag(kIsSubCollection);
+  }
+
+  ResetInput();
+  fCurrentEventId=kAliHLTVoidEventID;
+
+  return iResult;
+}
+
+int AliHLTOUT::ResetInput()
+{
+  // default implementation, nothing to do
+  return 0;
+}
+
+const AliHLTOUT::AliHLTOUTHandlerListEntry& AliHLTOUT::AliHLTOUTBlockDescriptor::GetHandlerDesc()
+{
+  // see header file for class documentation
+  if (fpCollection) {
+    AliHLTOUTHandlerListEntryVector::iterator element=fpCollection->fDataHandlers.begin();
+    while (element!=fpCollection->fDataHandlers.end()) {
+      if (element->HasIndex(GetIndex())) {
+       return *element;
+      }
+      element++;
+    }
+  }
+  return const_cast<AliHLTOUT::AliHLTOUTHandlerListEntry&>(AliHLTOUT::AliHLTOUTHandlerListEntry::fgkVoidHandlerListEntry);
+}
+
+TObject* AliHLTOUT::GetDataObject()
+{
+  // check if the current block encodes a ROOT object and expand it
+  if (fpDataObject) {
+    fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "data object has not been released, potential memory leak");
+    ReleaseDataBuffer(fpObjectBuffer);
+  }
+  fpObjectBuffer=NULL;
+  fObjectBufferSize=0;
+  fpDataObject=NULL;
+
+  if (GetDataBuffer(fpObjectBuffer, fObjectBufferSize)>=0) {
+    fpDataObject=AliHLTMessage::Extract(fpObjectBuffer, fObjectBufferSize);
+  } else {
+    fLog.LoggingVarargs(kHLTLogError, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "can not fetch data buffer");    
+  }
+
+  return fpDataObject;
+}
+
+int AliHLTOUT::ReleaseDataObject(TObject* pObject)
+{
+  // release a ROOT object previously expanded from the currentr data block
+  if (!pObject) return -EINVAL;
+  if (pObject!=fpDataObject) {
+    fLog.LoggingVarargs(kHLTLogError, "AliHLTOUT", "GetDataObject" , __FILE__ , __LINE__ , "attempt to release wrong data object %p, expected %p", pObject, fpDataObject);
+    return -EINVAL;
+  }
+
+  delete fpDataObject;
+  fpDataObject=NULL;
+  ReleaseDataBuffer(fpObjectBuffer);
+  fpObjectBuffer=NULL;
+  fObjectBufferSize=0;
+
+  return 0;
+}
+
+void AliHLTOUT::SetEventId(AliHLTUInt64_t id)
+{
+  // set event id
+  if (fCurrentEventId!=kAliHLTVoidEventID && fCurrentEventId!=id) {
+    fLog.LoggingVarargs(kHLTLogWarning, "AliHLTOUT", "SetEventId" , __FILE__ , __LINE__ , "event id was already set to 0x%llx, setting now to 0x%llx", fCurrentEventId, id);
+  }
+  fCurrentEventId=id;
+}
+
+void AliHLTOUT::Print(const char* option) const
+{
+  // print info
+  {
+    for (AliHLTOUTBlockDescriptorVector::const_iterator  i=fBlockDescList.begin();
+        i!=fBlockDescList.end(); i++)
+      i->Print(option);
+  }
+  {
+    for (AliHLTOUTHandlerListEntryVector::const_iterator  i=fDataHandlers.begin();
+        i!=fDataHandlers.end(); i++)
+      i->Print(option);
+  }
+}
+
+void AliHLTOUT::AliHLTOUTBlockDescriptor::Print(const char* /*option*/) const
+{
+  // print info
+  stringstream sout;
+  sout << "AliHLTOUTBlockDescriptor index 0x" << setfill('0') << setw(8) << hex << right << fIndex 
+       << ":   " << AliHLTComponent::DataType2Text(fDataType).c_str()
+       << "  0x" << setfill('0') << setw(8) << hex << fSpecification
+       << "  processed " << dec << fProcessed;
+  cout << sout.str() << endl;
+}
+
+void AliHLTOUT::AliHLTOUTHandlerListEntry::Print(const char* /*option*/) const
+{
+  // print info
+  stringstream sout;
+  AliHLTModuleAgent::AliHLTOUTHandlerType type=AliHLTModuleAgent::kUnknownOutput;
+  AliHLTComponentDataType dt=kAliHLTVoidDataType;
+  if (this->fpHandlerDesc) {
+    type=*(this->fpHandlerDesc);
+    dt=*(this->fpHandlerDesc);
+  }
+  const char* stype="";
+  switch(type) {
+  case AliHLTModuleAgent::kEsd: stype="ESD"; break;
+  case AliHLTModuleAgent::kRawReader: stype="RawReader"; break;
+  case AliHLTModuleAgent::kRawStream: stype="RawStream"; break;
+  case AliHLTModuleAgent::kChain: stype="Chain"; break;
+  case AliHLTModuleAgent::kProprietary: stype="Proprietary"; break;
+  default: stype="unknown";
+  }
+  sout << "HLTOUT handler: "
+       << "  " << type << " (" << stype << ")"
+       << "  " << AliHLTComponent::DataType2Text(dt).c_str();
+  cout << sout.str() << endl;
+}