<commit_before>// @(#)root/cont:$Name:  $:$Id: TRefTable.cxx,v 1.12 2006/05/14 08:25:47 brun Exp $
// Author: Rene Brun   28/09/2001

/*************************************************************************
 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// A TRefTable maintains the association between a referenced object    //
// and the parent object supporting this referenced object.             //
//                                                                      //
// The parent object is typically a branch of a TTree. For each object  //
// referenced in a TTree entry, the corresponding entry in the TTree's  //
// TBranchRef::fRefTable contains the index of the branch that          //
// needs to be loaded to bring the object into memory.                  //
//                                                                      //
// Persistency of a TRefTable is split into two parts:                  //
// * entry specific information is stored (read) by FillBuffer          //
//   (ReadBuffer). For each referenced object the object's fUniqueID    //
//   and the referencing TRef::fPID is stored (to allow the TRefTable   //
//   to autoload references created by different processes).            //
// * non-entry specific, i.e. global information is stored (read) by    //
//   the Streamer function. This comprises all members marked as        //
//   persistent.                                                        //
//                                                                      //
// As TObject::fUniqueID is only unique for a given TProcessID, a table //
// of unique IDs is kept for each used TProcessID. There is no natural  //
// order of TProcessIDs, so TRefTable stores a vector of the TGUID of   //
// all known TProcessIDs in fProcessGUIDs; the index of a TProcessID in //
// this vector defines the index of the auto-loading info in fParentIDs //
// for that TProcessID. The mapping of TProcessID* to index is cached   //
// for quick non-persistent lookup.                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRefTable.h"
#include "TObjArray.h"
#include "TVirtualIO.h"
#include "TProcessID.h"
#include <algorithm>

TRefTable *TRefTable::fgRefTable = 0;

ClassImp(TRefTable)
//______________________________________________________________________________
TRefTable::TRefTable()
{
   // Default constructor for I/O.

   fNumPIDs     = 0;
   fAllocSize   = 0;
   fN           = 0;
   fParentID    = -1;
   fParentIDs   = 0;
   fDefaultSize = 10;
   fParents     = 0;
   fOwner       = 0;
   fgRefTable   = this;
   fUID         = 0;
   fUIDContext  = 0;
}

//______________________________________________________________________________
TRefTable::TRefTable(TObject *owner, Int_t size)
{
   // Create a TRefTable with initial size.

   if (size < 10)
      size = 10;
   fNumPIDs     = 0;
   fAllocSize   = 0;
   fN           = 0;
   fParentID    = -1;
   fParentIDs   = 0;
   fDefaultSize = size;
   fParents     = new TObjArray(1);
   fOwner       = owner;
   fgRefTable   = this;
   fUID         = 0;
   fUIDContext  = 0;
}

//______________________________________________________________________________
TRefTable::~TRefTable()
{
   // Destructor.

   delete [] fAllocSize;
   delete [] fN;
   for (Int_t pid = 0; pid < fNumPIDs; ++pid)
      delete [] fParentIDs[pid];
   delete [] fParentIDs;
   delete fParents;
   if (fgRefTable == this) fgRefTable = 0;
}

//______________________________________________________________________________
Int_t TRefTable::Add(Int_t uid, TProcessID *context)
{
   // Add a new uid to the table.
   // we add a new pair (uid,fparent) to the map
   // This function is called by TObject::Streamer or TStreamerInfo::WriteBuffer

   if (!context)
      context = TProcessID::GetSessionProcessID();
   Int_t iid = GetInternalIdxForPID(context);

   Int_t newsize = 0;
   uid = uid & 0xffffff;
   if (uid >= fAllocSize[iid]) {
      newsize = uid + uid / 2;
      if (newsize < fDefaultSize)
         newsize = fDefaultSize;
      newsize = ExpandForIID(iid, newsize);
   }
   if (newsize < 0) {
      Error("Add", "Cannot allocate space to store uid=%d", uid);
      return -1;
   }
   if (fParentID < 0) {
      Error("Add", "SetParent must be called before adding uid=%d", uid);
      return -1;
   }
   fParentIDs[iid][uid] = fParentID + 1;
   if (uid >= fN[iid]) fN[iid] = uid + 1;
   return uid;
}

//______________________________________________________________________________
Int_t TRefTable::AddInternalIdxForPID(TProcessID *procid)
{
   // Add the internal index for fProcessIDs, fAllocSize, etc given a PID.

   if (!procid)
      procid = TProcessID::GetSessionProcessID();
   Int_t pid = procid->GetUniqueID();
   if (fMapPIDtoInternal.size() <= (size_t) pid)
      fMapPIDtoInternal.resize(TProcessID::GetNProcessIDs(), -1);

   Int_t iid = fMapPIDtoInternal[pid];
   if (iid == -1) {
      // need to update
      iid = FindPIDGUID(procid->GetTitle());
      if (iid == -1) {
         fProcessGUIDs.push_back(procid->GetTitle());
         iid = fProcessGUIDs.size() - 1;
      }
      fMapPIDtoInternal[pid] = iid;
   }

   ExpandPIDs(iid + 1);
   return iid;
}

//______________________________________________________________________________
void TRefTable::Clear(Option_t * /*option*/ )
{
   // Clear all entries in the table.

   for (Int_t iid = 0; iid < fNumPIDs; ++iid) {
      memset(fParentIDs[iid], 0, sizeof(Int_t) * fN[iid]);
   }
   memset(fN, 0, sizeof(Int_t) * fNumPIDs);
   fParentID = -1;
}

//______________________________________________________________________________
Int_t TRefTable::Expand(Int_t pid, Int_t newsize)
{
   // Expand fParentIDs to newsize for ProcessID pid.

   Int_t iid = GetInternalIdxForPID(pid);
   if (iid < 0) return -1;
   return ExpandForIID(iid, newsize);
}

//______________________________________________________________________________
Int_t TRefTable::ExpandForIID(Int_t iid, Int_t newsize)
{
   // Expand fParentIDs to newsize for internel ProcessID index iid.

   if (newsize < 0)  return newsize;
   if (newsize != fAllocSize[iid]) {
      Int_t *temp = fParentIDs[iid];
      if (newsize != 0) {
         fParentIDs[iid] = new Int_t[newsize];
         if (newsize < fAllocSize[iid])
            memcpy(fParentIDs[iid], temp, newsize * sizeof(Int_t));
         else {
            memcpy(fParentIDs[iid], temp, fAllocSize[iid] * sizeof(Int_t));
            memset(&fParentIDs[iid][fAllocSize[iid]], 0,
                   (newsize - fAllocSize[iid]) * sizeof(Int_t));
         }
      } else {
         fParentIDs[iid] = 0;
      }
      if (fAllocSize[iid]) delete [] temp;
      fAllocSize[iid] = newsize;
   }
   return newsize;
}

//______________________________________________________________________________
void TRefTable::ExpandPIDs(Int_t numpids)
{
   // Expand the arrays of managed PIDs

   if (numpids <= fNumPIDs) return;

   // else add to internal tables
   Int_t oldNumPIDs = fNumPIDs;
   fNumPIDs += numpids;

   Int_t *temp = fAllocSize;
   fAllocSize = new Int_t[fNumPIDs];
   if (temp) memcpy(fAllocSize, temp, oldNumPIDs * sizeof(Int_t));
   memset(&fAllocSize[oldNumPIDs], 0,
          (fNumPIDs - oldNumPIDs) * sizeof(Int_t));
   delete [] temp;

   temp = fN;
   fN = new Int_t[fNumPIDs];
   if (temp) memcpy(fN, temp, oldNumPIDs * sizeof(Int_t));
   memset(&fN[oldNumPIDs], 0, (fNumPIDs - oldNumPIDs) * sizeof(Int_t));
   delete [] temp;

   Int_t **temp2 = fParentIDs;
   fParentIDs = new Int_t *[fNumPIDs];
   if (temp2) memcpy(fParentIDs, temp2, oldNumPIDs * sizeof(Int_t *));
   memset(&fParentIDs[oldNumPIDs], 0,
          (fNumPIDs - oldNumPIDs) * sizeof(Int_t));
}

//______________________________________________________________________________
void TRefTable::FillBuffer(TBuffer & b)
{
   // Fill buffer b with the fN elements in fParentdIDs.
   // This function is called by TBranchRef::FillLeaves.

   b << -fNumPIDs; // write out "-" to signal new TRefTable buffer format using PID table
   for (Int_t iid = 0; iid < fNumPIDs; ++iid) {
      b << fN[iid];
      b.WriteFastArray(fParentIDs[iid], fN[iid]);
   }
}

//______________________________________________________________________________
Int_t TRefTable::FindPIDGUID(const char *guid) const
{
   // Get fProcessGUIDs' index of the TProcessID with GUID guid
   std::vector<std::string>::const_iterator posPID
      = std::find(fProcessGUIDs.begin(), fProcessGUIDs.end(), guid);
   if (posPID == fProcessGUIDs.end()) return -1;
   return posPID - fProcessGUIDs.begin();
}

//______________________________________________________________________________
TObject *TRefTable::GetParent(Int_t uid, TProcessID *context /* =0 */ ) const
{
   // Return object corresponding to uid.
   if (!fParents) return 0;

   Int_t iid = -1;
   if (!context) context = TProcessID::GetSessionProcessID();
   iid = GetInternalIdxForPID(context);

   uid = uid & 0xFFFFFF;
   if (uid < 0 || uid >= fN[iid]) return 0;
   Int_t pnumber = fParentIDs[iid][uid] - 1;
   Int_t nparents = fParents->GetEntriesFast();
   if (pnumber < 0 || pnumber >= nparents) return 0;
   return fParents->UncheckedAt(pnumber);
}

//______________________________________________________________________________
Int_t TRefTable::GetInternalIdxForPID(TProcessID *procid) const
{
   // Get the index for fProcessIDs, fAllocSize, etc given a PID.
   // Uses fMapPIDtoInternal and the pid's GUID / fProcessGUID

   return const_cast <TRefTable*>(this)->AddInternalIdxForPID(procid);
}

//______________________________________________________________________________
Int_t TRefTable::GetInternalIdxForPID(Int_t pid) const
{
   // Get the index for fProcessIDs, fAllocSize, etc given a PID.
   // Uses fMapPIDtoInternal and the pid's GUID / fProcessGUID

   return GetInternalIdxForPID(TProcessID::GetProcessID(pid));
}

//______________________________________________________________________________
TRefTable *TRefTable::GetRefTable()
{
   // Static function returning the current TRefTable.

   return fgRefTable;
}

//______________________________________________________________________________
Bool_t TRefTable::Notify()
{
   // This function is called by TRef::Streamer or TStreamerInfo::ReadBuffer
   // when reading a reference.
   // This function, in turns, notifies the TRefTable owner for action.
   // eg, when the owner is a TBranchRef, TBranchRef::Notify is called
   // to read the branch containing the referenced object.

   return fOwner->Notify();
}

//______________________________________________________________________________
void TRefTable::ReadBuffer(TBuffer &b)
{
   // Fill buffer b with the fN elements in fParentdIDs.
   // This function is called by TBranchRef::ReadLeaves

   Int_t firstInt = 0;          // we don't know yet what it means
   b >> firstInt;

   Int_t numIids = -1;
   Int_t startIid = 0;
   if (firstInt < 0) numIids = -firstInt; // new format
   else {
      // old format, only one PID
      numIids = 1;

      TProcessID *fileProcessID = TVirtualIO::GetIO()->GetLastProcessID(b,this);

      startIid = GetInternalIdxForPID(fileProcessID);
      if (startIid == -1) {
         fProcessGUIDs.push_back(fileProcessID->GetTitle());
         startIid = fProcessGUIDs.size() - 1;
      }
      numIids += startIid;
   }

   ExpandPIDs(numIids);
   for (Int_t iid = startIid; iid < numIids; ++iid) {
      Int_t newN = 0;
      if (firstInt < 0) b >> newN;
      else newN = firstInt;
      if (newN > fAllocSize[iid])
         ExpandForIID(iid, newN + newN / 2);
      fN[iid] = newN;
      b.ReadFastArray(fParentIDs[iid], fN[iid]);
   }
}

//______________________________________________________________________________
void TRefTable::Reset(Option_t * /*option*/ )
{
   // Clear all entries in the table.
   Clear();
   if (fParents) fParents->Clear();
}

//______________________________________________________________________________
Int_t TRefTable::SetParent(const TObject *parent)
{
   // Set Current parent object.
   // The parent object is typically a branch of a Tree.
   // This function is called by TBranchElement::Fill.

   if (!fParents)
      return 0;
   Int_t nparents = fParents->GetEntriesFast();
   Int_t ind = fParents->IndexOf(parent);
   if (ind >= 0) {
      fParentID = ind;
   } else {
      fParents->AddAtAndExpand((TObject*) parent, nparents);
      fParentID = nparents;
   }
   return fParentID;
}

//______________________________________________________________________________
void TRefTable::SetRefTable(TRefTable *table)
{
   // Static function setting the current TRefTable.

   fgRefTable = table;
}
<commit_msg>Replace the calls to TVirtualIO by new calls in TBuffer or TDirectory -------<commit_after>// @(#)root/cont:$Name:  $:$Id: TRefTable.cxx,v 1.13 2007/01/25 11:51:13 brun Exp $
// Author: Rene Brun   28/09/2001

/*************************************************************************
 * Copyright (C) 1995-2004, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// A TRefTable maintains the association between a referenced object    //
// and the parent object supporting this referenced object.             //
//                                                                      //
// The parent object is typically a branch of a TTree. For each object  //
// referenced in a TTree entry, the corresponding entry in the TTree's  //
// TBranchRef::fRefTable contains the index of the branch that          //
// needs to be loaded to bring the object into memory.                  //
//                                                                      //
// Persistency of a TRefTable is split into two parts:                  //
// * entry specific information is stored (read) by FillBuffer          //
//   (ReadBuffer). For each referenced object the object's fUniqueID    //
//   and the referencing TRef::fPID is stored (to allow the TRefTable   //
//   to autoload references created by different processes).            //
// * non-entry specific, i.e. global information is stored (read) by    //
//   the Streamer function. This comprises all members marked as        //
//   persistent.                                                        //
//                                                                      //
// As TObject::fUniqueID is only unique for a given TProcessID, a table //
// of unique IDs is kept for each used TProcessID. There is no natural  //
// order of TProcessIDs, so TRefTable stores a vector of the TGUID of   //
// all known TProcessIDs in fProcessGUIDs; the index of a TProcessID in //
// this vector defines the index of the auto-loading info in fParentIDs //
// for that TProcessID. The mapping of TProcessID* to index is cached   //
// for quick non-persistent lookup.                                     //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TRefTable.h"
#include "TObjArray.h"
#include "TProcessID.h"
#include <algorithm>

TRefTable *TRefTable::fgRefTable = 0;

ClassImp(TRefTable)
//______________________________________________________________________________
TRefTable::TRefTable()
{
   // Default constructor for I/O.

   fNumPIDs     = 0;
   fAllocSize   = 0;
   fN           = 0;
   fParentID    = -1;
   fParentIDs   = 0;
   fDefaultSize = 10;
   fParents     = 0;
   fOwner       = 0;
   fgRefTable   = this;
   fUID         = 0;
   fUIDContext  = 0;
}

//______________________________________________________________________________
TRefTable::TRefTable(TObject *owner, Int_t size)
{
   // Create a TRefTable with initial size.

   if (size < 10)
      size = 10;
   fNumPIDs     = 0;
   fAllocSize   = 0;
   fN           = 0;
   fParentID    = -1;
   fParentIDs   = 0;
   fDefaultSize = size;
   fParents     = new TObjArray(1);
   fOwner       = owner;
   fgRefTable   = this;
   fUID         = 0;
   fUIDContext  = 0;
}

//______________________________________________________________________________
TRefTable::~TRefTable()
{
   // Destructor.

   delete [] fAllocSize;
   delete [] fN;
   for (Int_t pid = 0; pid < fNumPIDs; ++pid)
      delete [] fParentIDs[pid];
   delete [] fParentIDs;
   delete fParents;
   if (fgRefTable == this) fgRefTable = 0;
}

//______________________________________________________________________________
Int_t TRefTable::Add(Int_t uid, TProcessID *context)
{
   // Add a new uid to the table.
   // we add a new pair (uid,fparent) to the map
   // This function is called by TObject::Streamer or TStreamerInfo::WriteBuffer

   if (!context)
      context = TProcessID::GetSessionProcessID();
   Int_t iid = GetInternalIdxForPID(context);

   Int_t newsize = 0;
   uid = uid & 0xffffff;
   if (uid >= fAllocSize[iid]) {
      newsize = uid + uid / 2;
      if (newsize < fDefaultSize)
         newsize = fDefaultSize;
      newsize = ExpandForIID(iid, newsize);
   }
   if (newsize < 0) {
      Error("Add", "Cannot allocate space to store uid=%d", uid);
      return -1;
   }
   if (fParentID < 0) {
      Error("Add", "SetParent must be called before adding uid=%d", uid);
      return -1;
   }
   fParentIDs[iid][uid] = fParentID + 1;
   if (uid >= fN[iid]) fN[iid] = uid + 1;
   return uid;
}

//______________________________________________________________________________
Int_t TRefTable::AddInternalIdxForPID(TProcessID *procid)
{
   // Add the internal index for fProcessIDs, fAllocSize, etc given a PID.

   if (!procid)
      procid = TProcessID::GetSessionProcessID();
   Int_t pid = procid->GetUniqueID();
   if (fMapPIDtoInternal.size() <= (size_t) pid)
      fMapPIDtoInternal.resize(TProcessID::GetNProcessIDs(), -1);

   Int_t iid = fMapPIDtoInternal[pid];
   if (iid == -1) {
      // need to update
      iid = FindPIDGUID(procid->GetTitle());
      if (iid == -1) {
         fProcessGUIDs.push_back(procid->GetTitle());
         iid = fProcessGUIDs.size() - 1;
      }
      fMapPIDtoInternal[pid] = iid;
   }

   ExpandPIDs(iid + 1);
   return iid;
}

//______________________________________________________________________________
void TRefTable::Clear(Option_t * /*option*/ )
{
   // Clear all entries in the table.

   for (Int_t iid = 0; iid < fNumPIDs; ++iid) {
      memset(fParentIDs[iid], 0, sizeof(Int_t) * fN[iid]);
   }
   memset(fN, 0, sizeof(Int_t) * fNumPIDs);
   fParentID = -1;
}

//______________________________________________________________________________
Int_t TRefTable::Expand(Int_t pid, Int_t newsize)
{
   // Expand fParentIDs to newsize for ProcessID pid.

   Int_t iid = GetInternalIdxForPID(pid);
   if (iid < 0) return -1;
   return ExpandForIID(iid, newsize);
}

//______________________________________________________________________________
Int_t TRefTable::ExpandForIID(Int_t iid, Int_t newsize)
{
   // Expand fParentIDs to newsize for internel ProcessID index iid.

   if (newsize < 0)  return newsize;
   if (newsize != fAllocSize[iid]) {
      Int_t *temp = fParentIDs[iid];
      if (newsize != 0) {
         fParentIDs[iid] = new Int_t[newsize];
         if (newsize < fAllocSize[iid])
            memcpy(fParentIDs[iid], temp, newsize * sizeof(Int_t));
         else {
            memcpy(fParentIDs[iid], temp, fAllocSize[iid] * sizeof(Int_t));
            memset(&fParentIDs[iid][fAllocSize[iid]], 0,
                   (newsize - fAllocSize[iid]) * sizeof(Int_t));
         }
      } else {
         fParentIDs[iid] = 0;
      }
      if (fAllocSize[iid]) delete [] temp;
      fAllocSize[iid] = newsize;
   }
   return newsize;
}

//______________________________________________________________________________
void TRefTable::ExpandPIDs(Int_t numpids)
{
   // Expand the arrays of managed PIDs

   if (numpids <= fNumPIDs) return;

   // else add to internal tables
   Int_t oldNumPIDs = fNumPIDs;
   fNumPIDs += numpids;

   Int_t *temp = fAllocSize;
   fAllocSize = new Int_t[fNumPIDs];
   if (temp) memcpy(fAllocSize, temp, oldNumPIDs * sizeof(Int_t));
   memset(&fAllocSize[oldNumPIDs], 0,
          (fNumPIDs - oldNumPIDs) * sizeof(Int_t));
   delete [] temp;

   temp = fN;
   fN = new Int_t[fNumPIDs];
   if (temp) memcpy(fN, temp, oldNumPIDs * sizeof(Int_t));
   memset(&fN[oldNumPIDs], 0, (fNumPIDs - oldNumPIDs) * sizeof(Int_t));
   delete [] temp;

   Int_t **temp2 = fParentIDs;
   fParentIDs = new Int_t *[fNumPIDs];
   if (temp2) memcpy(fParentIDs, temp2, oldNumPIDs * sizeof(Int_t *));
   memset(&fParentIDs[oldNumPIDs], 0,
          (fNumPIDs - oldNumPIDs) * sizeof(Int_t));
}

//______________________________________________________________________________
void TRefTable::FillBuffer(TBuffer & b)
{
   // Fill buffer b with the fN elements in fParentdIDs.
   // This function is called by TBranchRef::FillLeaves.

   b << -fNumPIDs; // write out "-" to signal new TRefTable buffer format using PID table
   for (Int_t iid = 0; iid < fNumPIDs; ++iid) {
      b << fN[iid];
      b.WriteFastArray(fParentIDs[iid], fN[iid]);
   }
}

//______________________________________________________________________________
Int_t TRefTable::FindPIDGUID(const char *guid) const
{
   // Get fProcessGUIDs' index of the TProcessID with GUID guid
   std::vector<std::string>::const_iterator posPID
      = std::find(fProcessGUIDs.begin(), fProcessGUIDs.end(), guid);
   if (posPID == fProcessGUIDs.end()) return -1;
   return posPID - fProcessGUIDs.begin();
}

//______________________________________________________________________________
TObject *TRefTable::GetParent(Int_t uid, TProcessID *context /* =0 */ ) const
{
   // Return object corresponding to uid.
   if (!fParents) return 0;

   Int_t iid = -1;
   if (!context) context = TProcessID::GetSessionProcessID();
   iid = GetInternalIdxForPID(context);

   uid = uid & 0xFFFFFF;
   if (uid < 0 || uid >= fN[iid]) return 0;
   Int_t pnumber = fParentIDs[iid][uid] - 1;
   Int_t nparents = fParents->GetEntriesFast();
   if (pnumber < 0 || pnumber >= nparents) return 0;
   return fParents->UncheckedAt(pnumber);
}

//______________________________________________________________________________
Int_t TRefTable::GetInternalIdxForPID(TProcessID *procid) const
{
   // Get the index for fProcessIDs, fAllocSize, etc given a PID.
   // Uses fMapPIDtoInternal and the pid's GUID / fProcessGUID

   return const_cast <TRefTable*>(this)->AddInternalIdxForPID(procid);
}

//______________________________________________________________________________
Int_t TRefTable::GetInternalIdxForPID(Int_t pid) const
{
   // Get the index for fProcessIDs, fAllocSize, etc given a PID.
   // Uses fMapPIDtoInternal and the pid's GUID / fProcessGUID

   return GetInternalIdxForPID(TProcessID::GetProcessID(pid));
}

//______________________________________________________________________________
TRefTable *TRefTable::GetRefTable()
{
   // Static function returning the current TRefTable.

   return fgRefTable;
}

//______________________________________________________________________________
Bool_t TRefTable::Notify()
{
   // This function is called by TRef::Streamer or TStreamerInfo::ReadBuffer
   // when reading a reference.
   // This function, in turns, notifies the TRefTable owner for action.
   // eg, when the owner is a TBranchRef, TBranchRef::Notify is called
   // to read the branch containing the referenced object.

   return fOwner->Notify();
}

//______________________________________________________________________________
void TRefTable::ReadBuffer(TBuffer &b)
{
   // Fill buffer b with the fN elements in fParentdIDs.
   // This function is called by TBranchRef::ReadLeaves

   Int_t firstInt = 0;          // we don't know yet what it means
   b >> firstInt;

   Int_t numIids = -1;
   Int_t startIid = 0;
   if (firstInt < 0) numIids = -firstInt; // new format
   else {
      // old format, only one PID
      numIids = 1;

      TProcessID *fileProcessID = b.GetLastProcessID(this);

      startIid = GetInternalIdxForPID(fileProcessID);
      if (startIid == -1) {
         fProcessGUIDs.push_back(fileProcessID->GetTitle());
         startIid = fProcessGUIDs.size() - 1;
      }
      numIids += startIid;
   }

   ExpandPIDs(numIids);
   for (Int_t iid = startIid; iid < numIids; ++iid) {
      Int_t newN = 0;
      if (firstInt < 0) b >> newN;
      else newN = firstInt;
      if (newN > fAllocSize[iid])
         ExpandForIID(iid, newN + newN / 2);
      fN[iid] = newN;
      b.ReadFastArray(fParentIDs[iid], fN[iid]);
   }
}

//______________________________________________________________________________
void TRefTable::Reset(Option_t * /*option*/ )
{
   // Clear all entries in the table.
   Clear();
   if (fParents) fParents->Clear();
}

//______________________________________________________________________________
Int_t TRefTable::SetParent(const TObject *parent)
{
   // Set Current parent object.
   // The parent object is typically a branch of a Tree.
   // This function is called by TBranchElement::Fill.

   if (!fParents)
      return 0;
   Int_t nparents = fParents->GetEntriesFast();
   Int_t ind = fParents->IndexOf(parent);
   if (ind >= 0) {
      fParentID = ind;
   } else {
      fParents->AddAtAndExpand((TObject*) parent, nparents);
      fParentID = nparents;
   }
   return fParentID;
}

//______________________________________________________________________________
void TRefTable::SetRefTable(TRefTable *table)
{
   // Static function setting the current TRefTable.

   fgRefTable = table;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/profiler_ui.h"

#include <string>

// When testing the javacript code, it is cumbersome to have to keep
// re-building the resouces package and reloading the browser. To solve
// this, enable the following flag to read the webapp's source files
// directly off disk, so all you have to do is refresh the page to
// test the modifications.
//#define USE_SOURCE_FILES_DIRECTLY

#include "base/bind.h"
#include "base/tracked_objects.h"
#include "chrome/browser/metrics/tracking_synchronizer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/common/url_constants.h"
#include "content/browser/trace_controller.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"

#ifdef USE_SOURCE_FILES_DIRECTLY
#include "base/base_paths.h"
#include "base/file_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
#endif  //  USE_SOURCE_FILES_DIRECTLY

using chrome_browser_metrics::TrackingSynchronizer;
using content::BrowserThread;
using content::WebContents;
using content::WebUIMessageHandler;

namespace {

#ifdef USE_SOURCE_FILES_DIRECTLY

class ProfilerWebUIDataSource : public ChromeURLDataManager::DataSource {
 public:
  ProfilerWebUIDataSource()
      : DataSource(chrome::kChromeUIProfilerHost, MessageLoop::current()) {
  }

 protected:
  // ChromeURLDataManager
  virtual std::string GetMimeType(const std::string& path) const OVERRIDE {
    if (EndsWith(path, ".js", false))
      return "application/javascript";
    return "text/html";
  }

  virtual void StartDataRequest(const std::string& path,
                                bool is_incognito,
                                int request_id) OVERRIDE {
    FilePath base_path;
    PathService::Get(base::DIR_SOURCE_ROOT, &base_path);
    base_path = base_path.AppendASCII("chrome");
    base_path = base_path.AppendASCII("browser");
    base_path = base_path.AppendASCII("resources");
    base_path = base_path.AppendASCII("profiler");

    // If no resource was specified, default to profiler.html.
    std::string filename = path.empty() ? "profiler.html" : path;

    FilePath file_path;
    file_path = base_path.AppendASCII(filename);

    // Read the file synchronously and send it as the response.
    base::ThreadRestrictions::ScopedAllowIO allow;
    std::string file_contents;
    if (!file_util::ReadFileToString(file_path, &file_contents))
      LOG(ERROR) << "Couldn't read file: " << file_path.value();
    scoped_refptr<base::RefCountedString> response =
        new base::RefCountedString();
    response->data() = file_contents;
    SendResponse(request_id, response);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(ProfilerWebUIDataSource);
};

ChromeURLDataManager::DataSource* CreateProfilerHTMLSource() {
  return new ProfilerWebUIDataSource();
}

#else  // USE_SOURCE_FILES_DIRECTLY

ChromeWebUIDataSource* CreateProfilerHTMLSource() {
  ChromeWebUIDataSource* source =
      new ChromeWebUIDataSource(chrome::kChromeUIProfilerHost);

  source->set_json_path("strings.js");
  source->add_resource_path("profiler.js", IDR_PROFILER_JS);
  source->set_default_resource(IDR_PROFILER_HTML);
  return source;
}

#endif

// This class receives javascript messages from the renderer.
// Note that the WebUI infrastructure runs on the UI thread, therefore all of
// this class's methods are expected to run on the UI thread.
class ProfilerMessageHandler : public WebUIMessageHandler {
 public:
  ProfilerMessageHandler() {}

  // WebUIMessageHandler implementation.
  virtual void RegisterMessages() OVERRIDE;

  // Messages.
  void OnGetData(const ListValue* list);
  void OnResetData(const ListValue* list);

 private:
  DISALLOW_COPY_AND_ASSIGN(ProfilerMessageHandler);
};

void ProfilerMessageHandler::RegisterMessages() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  web_ui()->RegisterMessageCallback("getData",
      base::Bind(&ProfilerMessageHandler::OnGetData,base::Unretained(this)));
  web_ui()->RegisterMessageCallback("resetData",
      base::Bind(&ProfilerMessageHandler::OnResetData,
                 base::Unretained(this)));
}

void ProfilerMessageHandler::OnGetData(const ListValue* list) {
  ProfilerUI* profiler_ui = reinterpret_cast<ProfilerUI*>(web_ui());
  profiler_ui->GetData();
}

void ProfilerMessageHandler::OnResetData(const ListValue* list) {
  tracked_objects::ThreadData::ResetAllThreadData();
}

}  // namespace

ProfilerUI::ProfilerUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  ui_weak_ptr_factory_.reset(new base::WeakPtrFactory<ProfilerUI>(this));
  ui_weak_ptr_ = ui_weak_ptr_factory_->GetWeakPtr();

  web_ui->AddMessageHandler(new ProfilerMessageHandler());

  // Set up the chrome://profiler/ source.
  Profile::FromWebUI(web_ui)->
      GetChromeURLDataManager()->AddDataSource(CreateProfilerHTMLSource());
}

ProfilerUI::~ProfilerUI() {
}

void ProfilerUI::GetData() {
  TrackingSynchronizer::FetchProfilerDataAsynchronously(ui_weak_ptr_);
}

void ProfilerUI::ReceivedData(base::Value* value) {
  // Send the data to the renderer.
  scoped_ptr<Value> data_values(value);
  web_ui()->CallJavascriptFunction(
      "g_browserBridge.receivedData", *data_values.get());
}

<commit_msg>Fix about:profiler crash.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui/profiler_ui.h"

#include <string>

// When testing the javacript code, it is cumbersome to have to keep
// re-building the resouces package and reloading the browser. To solve
// this, enable the following flag to read the webapp's source files
// directly off disk, so all you have to do is refresh the page to
// test the modifications.
//#define USE_SOURCE_FILES_DIRECTLY

#include "base/bind.h"
#include "base/tracked_objects.h"
#include "chrome/browser/metrics/tracking_synchronizer.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/chrome_web_ui_data_source.h"
#include "chrome/common/url_constants.h"
#include "content/browser/trace_controller.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_message_handler.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"

#ifdef USE_SOURCE_FILES_DIRECTLY
#include "base/base_paths.h"
#include "base/file_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/path_service.h"
#endif  //  USE_SOURCE_FILES_DIRECTLY

using chrome_browser_metrics::TrackingSynchronizer;
using content::BrowserThread;
using content::WebContents;
using content::WebUIMessageHandler;

namespace {

#ifdef USE_SOURCE_FILES_DIRECTLY

class ProfilerWebUIDataSource : public ChromeURLDataManager::DataSource {
 public:
  ProfilerWebUIDataSource()
      : DataSource(chrome::kChromeUIProfilerHost, MessageLoop::current()) {
  }

 protected:
  // ChromeURLDataManager
  virtual std::string GetMimeType(const std::string& path) const OVERRIDE {
    if (EndsWith(path, ".js", false))
      return "application/javascript";
    return "text/html";
  }

  virtual void StartDataRequest(const std::string& path,
                                bool is_incognito,
                                int request_id) OVERRIDE {
    FilePath base_path;
    PathService::Get(base::DIR_SOURCE_ROOT, &base_path);
    base_path = base_path.AppendASCII("chrome");
    base_path = base_path.AppendASCII("browser");
    base_path = base_path.AppendASCII("resources");
    base_path = base_path.AppendASCII("profiler");

    // If no resource was specified, default to profiler.html.
    std::string filename = path.empty() ? "profiler.html" : path;

    FilePath file_path;
    file_path = base_path.AppendASCII(filename);

    // Read the file synchronously and send it as the response.
    base::ThreadRestrictions::ScopedAllowIO allow;
    std::string file_contents;
    if (!file_util::ReadFileToString(file_path, &file_contents))
      LOG(ERROR) << "Couldn't read file: " << file_path.value();
    scoped_refptr<base::RefCountedString> response =
        new base::RefCountedString();
    response->data() = file_contents;
    SendResponse(request_id, response);
  }

 private:
  DISALLOW_COPY_AND_ASSIGN(ProfilerWebUIDataSource);
};

ChromeURLDataManager::DataSource* CreateProfilerHTMLSource() {
  return new ProfilerWebUIDataSource();
}

#else  // USE_SOURCE_FILES_DIRECTLY

ChromeWebUIDataSource* CreateProfilerHTMLSource() {
  ChromeWebUIDataSource* source =
      new ChromeWebUIDataSource(chrome::kChromeUIProfilerHost);

  source->set_json_path("strings.js");
  source->add_resource_path("profiler.js", IDR_PROFILER_JS);
  source->set_default_resource(IDR_PROFILER_HTML);
  return source;
}

#endif

// This class receives javascript messages from the renderer.
// Note that the WebUI infrastructure runs on the UI thread, therefore all of
// this class's methods are expected to run on the UI thread.
class ProfilerMessageHandler : public WebUIMessageHandler {
 public:
  ProfilerMessageHandler() {}

  // WebUIMessageHandler implementation.
  virtual void RegisterMessages() OVERRIDE;

  // Messages.
  void OnGetData(const ListValue* list);
  void OnResetData(const ListValue* list);

 private:
  DISALLOW_COPY_AND_ASSIGN(ProfilerMessageHandler);
};

void ProfilerMessageHandler::RegisterMessages() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  web_ui()->RegisterMessageCallback("getData",
      base::Bind(&ProfilerMessageHandler::OnGetData,base::Unretained(this)));
  web_ui()->RegisterMessageCallback("resetData",
      base::Bind(&ProfilerMessageHandler::OnResetData,
                 base::Unretained(this)));
}

void ProfilerMessageHandler::OnGetData(const ListValue* list) {
  ProfilerUI* profiler_ui = static_cast<ProfilerUI*>(web_ui()->GetController());
  profiler_ui->GetData();
}

void ProfilerMessageHandler::OnResetData(const ListValue* list) {
  tracked_objects::ThreadData::ResetAllThreadData();
}

}  // namespace

ProfilerUI::ProfilerUI(content::WebUI* web_ui) : WebUIController(web_ui) {
  ui_weak_ptr_factory_.reset(new base::WeakPtrFactory<ProfilerUI>(this));
  ui_weak_ptr_ = ui_weak_ptr_factory_->GetWeakPtr();

  web_ui->AddMessageHandler(new ProfilerMessageHandler());

  // Set up the chrome://profiler/ source.
  Profile::FromWebUI(web_ui)->
      GetChromeURLDataManager()->AddDataSource(CreateProfilerHTMLSource());
}

ProfilerUI::~ProfilerUI() {
}

void ProfilerUI::GetData() {
  TrackingSynchronizer::FetchProfilerDataAsynchronously(ui_weak_ptr_);
}

void ProfilerUI::ReceivedData(base::Value* value) {
  // Send the data to the renderer.
  scoped_ptr<Value> data_values(value);
  web_ui()->CallJavascriptFunction(
      "g_browserBridge.receivedData", *data_values.get());
}

<|endoftext|>


<commit_before>#include "umundo/core.h"
#include <iostream>

using namespace umundo;

bool testRecursiveMutex() {
	Mutex mutex;
	UMUNDO_LOCK(mutex);
	if(!mutex.tryLock()) {
		LOG_ERR("tryLock should be possible from within the same thread");
		assert(false);
	}
	UMUNDO_LOCK(mutex);
	// can we unlock it as well?
	UMUNDO_UNLOCK(mutex);
	UMUNDO_UNLOCK(mutex);
	return true;
}

static Mutex testMutex;
bool testThreads() {
	class Thread1 : public Thread {
		void run() {
			if(testMutex.tryLock()) {
				LOG_ERR("tryLock should return false with a mutex locked in another thread");
				assert(false);
			}
			UMUNDO_LOCK(testMutex); // blocks
			Thread::sleepMs(50);
			UMUNDO_UNLOCK(testMutex);
			Thread::sleepMs(100);
		}
	};

	/**
	 * tl=tryLock, l=lock, u=unlock b=block, sN=sleep(N)
	 * thread1:        start tl l  l s50      u
	 *    main: start l s50       u s20  tl    l join
	 *    t->          0         50     70   100
	 */

	UMUNDO_LOCK(testMutex);
	Thread1 thread1;
	thread1.start();
	Thread::sleepMs(50); // thread1 will trylock and block on lock
	UMUNDO_UNLOCK(testMutex);  // unlock
	Thread::sleepMs(20); // yield cpu and sleep
	// thread1 sleeps with lock on mutex
	if(testMutex.tryLock()) {
		LOG_ERR("tryLock should return false with a mutex locked in another thread");
		assert(false);
	}
	UMUNDO_LOCK(testMutex);    // thread1 will unlock and sleep
	thread1.join();      // join with thread1
	if(thread1.isStarted()) {
		LOG_ERR("thread still running after join");
		assert(false);
	}
	return true;
}

static Monitor testMonitor;
static int passedMonitor = 0;
bool testMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testMonitor.wait();
			Thread::sleepMs(10); // avoid clash with other threads
			passedMonitor++;
		}
	};

	TestThread thread1(0);
	TestThread thread2(5);
	TestThread thread3(10);

	for (int i = 0; i < 10; i++) {
		passedMonitor = 0;

		// all will block on monitor
		thread1.start();
		thread2.start();
		thread3.start();
		Thread::sleepMs(5); // give threads a chance to run into wait
		if(passedMonitor != 0) {
			LOG_ERR("%d threads already passed the monitor", passedMonitor);
			assert(false);
		}
		UMUNDO_SIGNAL(testMonitor); // signal a single thread
		Thread::sleepMs(15); // thread will increase passedMonitor
		if(passedMonitor != 1) {
			LOG_ERR("Expected 1 threads to pass the monitor, but %d did", passedMonitor);
			assert(false);
		}
		UMUNDO_BROADCAST(testMonitor); // signal all other threads
		Thread::sleepMs(15);

		if (thread1.isStarted() || thread2.isStarted() || thread3.isStarted()) {
			LOG_ERR("Threads ran to completion but still insist on being started");
			assert(false);
		}
	}
	return true;
}

static Monitor testTimedMonitor;
static int passedTimedMonitor = 0;
bool testTimedMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testTimedMonitor.wait(_ms);
			passedTimedMonitor++;
		}
	};

	TestThread thread1(15);
	TestThread thread2(0); // waits forever
	TestThread thread3(0); // waits forever
	TestThread thread4(0); // waits forever
	TestThread thread5(0); // waits forever

	for (int i = 0; i < 50; i++) {
		// test waiting for a given time
		passedTimedMonitor = 0;
		thread1.start(); // wait for 15ms at mutex before resuming
		Thread::sleepMs(5);
		assert(passedTimedMonitor == 0); // thread1 should not have passed
		Thread::sleepMs(25);
		assert(passedTimedMonitor == 1); // thread1 should have passed
		assert(!thread1.isStarted());

		// test signalling a set of threads
		passedTimedMonitor = 0;
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		Thread::sleepMs(5);
		testTimedMonitor.signal(2); // signal 2 threads
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 2);
		testTimedMonitor.signal(1); // signal another thread
		Thread::sleepMs(5);
		assert(passedTimedMonitor == 3);
		testTimedMonitor.broadcast(); // signal last thread
		Thread::sleepMs(5);
		assert(passedTimedMonitor == 4);
		assert(!thread2.isStarted() && !thread3.isStarted() && !thread4.isStarted() && !thread5.isStarted());

		// test timed and unlimited waiting
		passedTimedMonitor = 0;
		thread1.start();
		thread2.start(); // with another thread
		thread3.start(); // with another thread
		Thread::sleepMs(5);
		testTimedMonitor.signal(); // explicit signal
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 1);
		// wo do not know which thread passed
		assert(!thread1.isStarted() || !thread2.isStarted() || !thread3.isStarted());
		if (thread1.isStarted()) {
			// thread1 is still running, just wait
			Thread::sleepMs(10);
			assert(passedTimedMonitor == 2);
		}
		testTimedMonitor.broadcast(); // explicit signal
		Thread::sleepMs(5);
		assert(passedTimedMonitor == 3);
		assert(!thread1.isStarted() && !thread2.isStarted() && !thread3.isStarted());

		// test signalling prior to waiting
		passedTimedMonitor = 0;
		testTimedMonitor.signal();
		thread1.start();
		Thread::sleepMs(5);
		thread2.start();
		Thread::sleepMs(5);
		assert(passedTimedMonitor == 1);
		assert(!thread1.isStarted());
		assert(thread2.isStarted());
		testTimedMonitor.signal();
		Thread::sleepMs(5);
		assert(passedTimedMonitor == 2);

		assert(!thread1.isStarted());
		assert(!thread2.isStarted());
		assert(!thread3.isStarted());

	}
	return true;
}

class FooTracer : public Traceable, public Thread {
	void run() {
		while(isStarted()) {
			trace("This is foo");
			Thread::sleepMs(20);
		}
	}
};

bool testTracing() {
	FooTracer* tr1 = new FooTracer();
	FooTracer* tr2 = new FooTracer();
	FooTracer* tr3 = new FooTracer();

	tr1->setTraceFile("trace.txt");
	tr2->setTraceFile("trace.txt");
	tr3->setTraceFile("trace.txt");

	tr1->start();
	tr2->start();
	tr3->start();

	Thread::sleepMs(100);
	delete tr1;
	delete tr2;
	delete tr3;

	return true;
}

int main(int argc, char** argv) {
	if(!testTracing())
		return EXIT_FAILURE;
	if(!testRecursiveMutex())
		return EXIT_FAILURE;
	if(!testThreads())
		return EXIT_FAILURE;
	if(!testMonitors())
		return EXIT_FAILURE;
	if(!testTimedMonitors())
		return EXIT_FAILURE;
}
<commit_msg>increased timeouts<commit_after>#include "umundo/core.h"
#include <iostream>

using namespace umundo;

bool testRecursiveMutex() {
	Mutex mutex;
	UMUNDO_LOCK(mutex);
	if(!mutex.tryLock()) {
		LOG_ERR("tryLock should be possible from within the same thread");
		assert(false);
	}
	UMUNDO_LOCK(mutex);
	// can we unlock it as well?
	UMUNDO_UNLOCK(mutex);
	UMUNDO_UNLOCK(mutex);
	return true;
}

static Mutex testMutex;
bool testThreads() {
	class Thread1 : public Thread {
		void run() {
			if(testMutex.tryLock()) {
				LOG_ERR("tryLock should return false with a mutex locked in another thread");
				assert(false);
			}
			UMUNDO_LOCK(testMutex); // blocks
			Thread::sleepMs(50);
			UMUNDO_UNLOCK(testMutex);
			Thread::sleepMs(100);
		}
	};

	/**
	 * tl=tryLock, l=lock, u=unlock b=block, sN=sleep(N)
	 * thread1:        start tl l  l s50      u
	 *    main: start l s50       u s20  tl    l join
	 *    t->          0         50     70   100
	 */

	UMUNDO_LOCK(testMutex);
	Thread1 thread1;
	thread1.start();
	Thread::sleepMs(50); // thread1 will trylock and block on lock
	UMUNDO_UNLOCK(testMutex);  // unlock
	Thread::sleepMs(20); // yield cpu and sleep
	// thread1 sleeps with lock on mutex
	if(testMutex.tryLock()) {
		LOG_ERR("tryLock should return false with a mutex locked in another thread");
		assert(false);
	}
	UMUNDO_LOCK(testMutex);    // thread1 will unlock and sleep
	thread1.join();      // join with thread1
	if(thread1.isStarted()) {
		LOG_ERR("thread still running after join");
		assert(false);
	}
	return true;
}

static Monitor testMonitor;
static int passedMonitor = 0;
bool testMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testMonitor.wait();
			Thread::sleepMs(10); // avoid clash with other threads
			passedMonitor++;
		}
	};

	TestThread thread1(0);
	TestThread thread2(5);
	TestThread thread3(10);

	for (int i = 0; i < 10; i++) {
		passedMonitor = 0;

		// all will block on monitor
		thread1.start();
		thread2.start();
		thread3.start();
		Thread::sleepMs(5); // give threads a chance to run into wait
		if(passedMonitor != 0) {
			LOG_ERR("%d threads already passed the monitor", passedMonitor);
			assert(false);
		}
		UMUNDO_SIGNAL(testMonitor); // signal a single thread
		Thread::sleepMs(15); // thread will increase passedMonitor
		if(passedMonitor != 1) {
			LOG_ERR("Expected 1 threads to pass the monitor, but %d did", passedMonitor);
			assert(false);
		}
		UMUNDO_BROADCAST(testMonitor); // signal all other threads
		Thread::sleepMs(15);

		if (thread1.isStarted() || thread2.isStarted() || thread3.isStarted()) {
			LOG_ERR("Threads ran to completion but still insist on being started");
			assert(false);
		}
	}
	return true;
}

static Monitor testTimedMonitor;
static int passedTimedMonitor = 0;
bool testTimedMonitors() {
	struct TestThread : public Thread {
		int _ms;
		TestThread(int ms) : _ms(ms) {}
		void run() {
			testTimedMonitor.wait(_ms);
			passedTimedMonitor++;
		}
	};

	TestThread thread1(40);
	TestThread thread2(0); // waits forever
	TestThread thread3(0); // waits forever
	TestThread thread4(0); // waits forever
	TestThread thread5(0); // waits forever

	for (int i = 0; i < 10; i++) {
		// test waiting for a given time
		passedTimedMonitor = 0;
		thread1.start(); // wait for 15ms at mutex before resuming
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 0); // thread1 should not have passed
		Thread::sleepMs(60);
		assert(passedTimedMonitor == 1); // thread1 should have passed
		assert(!thread1.isStarted());

		// test signalling a set of threads
		passedTimedMonitor = 0;
		thread2.start();
		thread3.start();
		thread4.start();
		thread5.start();
		Thread::sleepMs(5);
		testTimedMonitor.signal(2); // signal 2 threads
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 2);
		testTimedMonitor.signal(1); // signal another thread
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 3);
		testTimedMonitor.broadcast(); // signal last thread
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 4);
		assert(!thread2.isStarted() && !thread3.isStarted() && !thread4.isStarted() && !thread5.isStarted());

		// test timed and unlimited waiting
		passedTimedMonitor = 0;
		thread1.start();
		thread2.start(); // with another thread
		thread3.start(); // with another thread
		Thread::sleepMs(5);
		testTimedMonitor.signal(); // explicit signal
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 1);
		// wo do not know which thread passed
		assert(!thread1.isStarted() || !thread2.isStarted() || !thread3.isStarted());
		if (thread1.isStarted()) {
			// thread1 is still running, just wait
			Thread::sleepMs(60);
			assert(passedTimedMonitor == 2);
		}
		testTimedMonitor.broadcast(); // explicit signal
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 3);
		assert(!thread1.isStarted() && !thread2.isStarted() && !thread3.isStarted());

		// test signalling prior to waiting
		passedTimedMonitor = 0;
		testTimedMonitor.signal();
		thread1.start();
		Thread::sleepMs(10);
		thread2.start();
		Thread::sleepMs(10);
		assert(passedTimedMonitor == 1);
		assert(!thread1.isStarted());
		assert(thread2.isStarted());
		testTimedMonitor.signal();
		Thread::sleepMs(20);
		assert(passedTimedMonitor == 2);

		assert(!thread1.isStarted());
		assert(!thread2.isStarted());
		assert(!thread3.isStarted());

	}
	return true;
}

class FooTracer : public Traceable, public Thread {
	void run() {
		while(isStarted()) {
			trace("This is foo");
			Thread::sleepMs(20);
		}
	}
};

bool testTracing() {
	FooTracer* tr1 = new FooTracer();
	FooTracer* tr2 = new FooTracer();
	FooTracer* tr3 = new FooTracer();

	tr1->setTraceFile("trace.txt");
	tr2->setTraceFile("trace.txt");
	tr3->setTraceFile("trace.txt");

	tr1->start();
	tr2->start();
	tr3->start();

	Thread::sleepMs(100);
	delete tr1;
	delete tr2;
	delete tr3;

	return true;
}

int main(int argc, char** argv) {
	if(!testTracing())
		return EXIT_FAILURE;
	if(!testRecursiveMutex())
		return EXIT_FAILURE;
	if(!testThreads())
		return EXIT_FAILURE;
	if(!testMonitors())
		return EXIT_FAILURE;
	if(!testTimedMonitors())
		return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>#include "SummarizationSubManager.h"
#include "ParentKeyStorage.h"
#include "SummarizationStorage.h"
#include "CommentCacheStorage.h"
#include "splm.h"

#include <index-manager/IndexManager.h>
#include <document-manager/DocumentManager.h>

#include <common/ScdParser.h>
#include <idmlib/util/idm_analyzer.h>

#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/algorithm/string.hpp>

#include <glog/logging.h>

#include <iostream>
#include <vector>
#include <algorithm>

using namespace izenelib::ir::indexmanager;
namespace bfs = boost::filesystem;

namespace sf1r
{

static const UString DOCID("DOCID", UString::UTF_8);

bool CheckParentKeyLogFormat(
        const SCDDocPtr& doc,
        const UString& parent_key_name)
{
    if (doc->size() != 2) return false;
    const UString& first = (*doc)[0].first;
    const UString& second = (*doc)[1].first;
    //FIXME case insensitive compare, but it requires extra string conversion,
    //which introduces unnecessary memory fragments
    return (first == DOCID && second == parent_key_name);
}

struct IsParentKeyFilterProperty
{
    const std::string& parent_key_property;

    IsParentKeyFilterProperty(const std::string& property)
        : parent_key_property(property)
    {}

    bool operator()(const QueryFiltering::FilteringType& filterType)
    {
        return boost::iequals(parent_key_property, filterType.property_);
    }
};

MultiDocSummarizationSubManager::MultiDocSummarizationSubManager(
        const std::string& homePath,
        SummarizeConfig schema,
        boost::shared_ptr<DocumentManager> document_manager,
        boost::shared_ptr<IndexManager> index_manager,
        idmlib::util::IDMAnalyzer* analyzer)
    : schema_(schema)
    , parent_key_ustr_name_(schema_.parentKey, UString::UTF_8)
    , document_manager_(document_manager)
    , index_manager_(index_manager)
    , analyzer_(analyzer)
    , comment_cache_storage_(new CommentCacheStorage(homePath + "/comment_cache"))
    , parent_key_storage_(new ParentKeyStorage(homePath, comment_cache_storage_))
    , summarization_storage_(new SummarizationStorage(homePath + "/summarization"))
    , corpus_(new Corpus())
{
    if (!schema_.parentKeyLogPath.empty())
        bfs::create_directories(schema_.parentKeyLogPath);
}

MultiDocSummarizationSubManager::~MultiDocSummarizationSubManager()
{
    delete parent_key_storage_;
    delete summarization_storage_;
    delete comment_cache_storage_;
    delete corpus_;
}

void MultiDocSummarizationSubManager::EvaluateSummarization()
{
    BuildIndexOfParentKey_();

    if (schema_.parentKeyLogPath.empty())
    {
        for (uint32_t i = 1; i <= document_manager_->getMaxDocId(); i++)
        {
            Document doc;
            document_manager_->getDocument(i, doc);
            Document::property_const_iterator kit = doc.findProperty(schema_.foreignKeyPropName);
            if (kit == doc.propertyEnd())
                continue;

            Document::property_const_iterator cit = doc.findProperty(schema_.contentPropName);
            if (cit == doc.propertyEnd())
                continue;

            const UString& key = kit->second.get<UString>();
            const UString& content = cit->second.get<UString>();
            comment_cache_storage_->AppendUpdate(key, i, content);
        }
    }
    else
    {
        for (uint32_t i = 1; i <= document_manager_->getMaxDocId(); i++)
        {
            Document doc;
            document_manager_->getDocument(i, doc);
            Document::property_const_iterator kit = doc.findProperty(schema_.foreignKeyPropName);
            if (kit == doc.propertyEnd())
                continue;

            Document::property_const_iterator cit = doc.findProperty(schema_.contentPropName);
            if (cit == doc.propertyEnd())
                continue;

            const UString& key = kit->second.get<UString>();
            UString parent_key;
            if (!parent_key_storage_->GetParent(key, parent_key))
                continue;

            const UString& content = cit->second.get<UString>();
            comment_cache_storage_->AppendUpdate(parent_key, i, content);
        }
    }
    comment_cache_storage_->Flush();

    CommentCacheStorage::CommentCacheIteratorType commentCacheIt(comment_cache_storage_->comment_cache_db_);
    CommentCacheStorage::CommentCacheIteratorType commentCacheEnd;
    for (; commentCacheIt != commentCacheEnd; ++commentCacheIt)
    {
        const UString& key = commentCacheIt->first;
        Summarization summarization(commentCacheIt->second.first);
        DoEvaluateSummarization_(summarization, key, commentCacheIt->second.second);
    }
    summarization_storage_->Flush();
}

void MultiDocSummarizationSubManager::DoEvaluateSummarization_(
        Summarization& summarization,
        const UString& key,
        const std::vector<UString>& content_list)
{
    if (!summarization_storage_->IsRebuildSummarizeRequired(key, summarization))
        return;

#define MAXDOC 100

    ilplib::langid::Analyzer* langIdAnalyzer = document_manager_->getLangId();
    corpus_->start_new_coll(key);
    corpus_->start_new_doc(); // XXX

    for (std::vector<UString>::const_iterator it = content_list.begin();
            it != content_list.end(); ++it)
    {
        // XXX
        // corpus_->start_new_doc();

        const UString& content = *it;
        UString sentence;
        std::size_t startPos = 0;
        while (std::size_t len = langIdAnalyzer->sentenceLength(content, startPos))
        {
            sentence.assign(content, startPos, len);

            corpus_->start_new_sent(sentence);

            std::vector<UString> word_list;
            analyzer_->GetStringList(sentence, word_list);
            for (std::vector<UString>::const_iterator wit = word_list.begin();
                    wit != word_list.end(); ++wit)
            {
                corpus_->add_word(*wit);
            }

            startPos += len;
        }
    }
    corpus_->start_new_sent();
    corpus_->start_new_doc();
    corpus_->start_new_coll();

    std::map<UString, std::vector<std::pair<double, UString> > > summaries;
//#define DEBUG_SUMMARIZATION
#ifdef DEBUG_SUMMARIZATION
    std::string key_str;
    key.convertString(key_str, UString::UTF_8);
    std::cout << "Begin evaluating: " << key_str << std::endl;
#endif
    if (content_list.size() < 2000 && corpus_->ntotal() < 100000)
    {
        SPLM::generateSummary(summaries, *corpus_, SPLM::SPLM_RI);
    }
    else
    {
        SPLM::generateSummary(summaries, *corpus_, SPLM::SPLM_NONE);
    }
#ifdef DEBUG_SUMMARIZATION
    std::cout << "End evaluating: " << key_str << std::endl;
#endif

    //XXX store the generated summary list
    std::vector<std::pair<double, UString> >& summary_list = summaries[key];
    if (!summary_list.empty())
    {
#ifdef DEBUG_SUMMARIZATION
        for (uint32_t i = 0; i < summary_list.size(); i++)
        {
            std::string sent;
            summary_list[i].second.convertString(sent, UString::UTF_8);
            std::cout << "\t" << sent << std::endl;
        }
#endif
        summarization.insertProperty("overview", summary_list);
    }
    summarization_storage_->Update(key, summarization);

    corpus_->reset();
}

bool MultiDocSummarizationSubManager::GetSummarizationByRawKey(
        const UString& rawKey,
        Summarization& result)
{
    return summarization_storage_->Get(rawKey, result);
}

void MultiDocSummarizationSubManager::AppendSearchFilter(
        std::vector<QueryFiltering::FilteringType>& filtingList)
{
    ///When search filter is based on ParentKey, get its associated values,
    ///and add those values to filter conditions.
    ///The typical situation of this happen when :
    ///SELECT * FROM comments WHERE product_type="foo"
    ///This hook will translate the semantic into:
    ///SELECT * FROM comments WHERE product_id="1" OR product_id="2" ...

    typedef std::vector<QueryFiltering::FilteringType>::iterator IteratorType;
    IteratorType it = std::find_if(filtingList.begin(),
            filtingList.end(), IsParentKeyFilterProperty(schema_.parentKey));
    if (it != filtingList.end())
    {
        const std::vector<PropertyValue>& filterParam = it->values_;
        if (!filterParam.empty())
        {
            try
            {
                const std::string& paramValue = get<std::string>(filterParam[0]);
                UString paramUStr(paramValue, UString::UTF_8);
                std::vector<UString> results;
                if (parent_key_storage_->GetChildren(paramUStr, results))
                {
                    BTreeIndexerManager* pBTreeIndexer = index_manager_->getBTreeIndexer();
                    QueryFiltering::FilteringType filterRule;
                    filterRule.operation_ = QueryFiltering::INCLUDE;
                    filterRule.property_ = schema_.foreignKeyPropName;
                    std::vector<UString>::const_iterator rit = results.begin();
                    for (; rit != results.end(); ++rit)
                    {
                        if (pBTreeIndexer->seek(schema_.foreignKeyPropName, *rit))
                        {
                            ///Protection
                            ///Or else, too many unexisted keys are added
                            PropertyValue v(*rit);
                            filterRule.values_.push_back(v);
                        }
                    }
                    //filterRule.logic_ = QueryFiltering::OR;
                    filtingList.erase(it);
                    //it->logic_ = QueryFiltering::OR;
                    filtingList.push_back(filterRule);
                }
            }
            catch (const boost::bad_get &)
            {
                filtingList.erase(it);
                return;
            }
        }
    }
}

void MultiDocSummarizationSubManager::BuildIndexOfParentKey_()
{
    if (schema_.parentKeyLogPath.empty()) return;
    ScdParser parser(UString::UTF_8);
    std::vector<std::string> scdList;
    static const bfs::directory_iterator kItrEnd;
    for (bfs::directory_iterator itr(schema_.parentKeyLogPath); itr != kItrEnd; ++itr)
    {
        if (bfs::is_regular_file(itr->status()))
        {
            std::string fileName = itr->path().filename().string();
            if (parser.checkSCDFormat(fileName))
            {
                scdList.push_back(itr->path().string());
            }
            else
            {
                LOG(WARNING) << "SCD File not valid " << fileName;
            }
        }
    }

    std::vector<std::string>::const_iterator scd_it = scdList.begin();

    for (; scd_it != scdList.end(); ++scd_it)
    {
        size_t pos = scd_it->rfind("/") + 1;
        string filename = scd_it->substr(pos);

        LOG(INFO) << "Processing SCD file. " << bfs::path(*scd_it).stem();

        switch (parser.checkSCDType(*scd_it))
        {
        case INSERT_SCD:
            DoInsertBuildIndexOfParentKey_(*scd_it);
            LOG(INFO) << "Indexing Finished";
            break;
        case DELETE_SCD:
            DoDelBuildIndexOfParentKey_(*scd_it);
            LOG(INFO) << "Delete Finished";
            break;
        case UPDATE_SCD:
            DoUpdateIndexOfParentKey_(*scd_it);
            LOG(INFO) << "Update Finished";
            break;
        default:
            break;
        }
        parser.load(*scd_it);
    }
    parent_key_storage_->Flush();

    bfs::path bkDir = bfs::path(schema_.parentKeyLogPath) / "backup";
    bfs::create_directory(bkDir);
    LOG(INFO) << "moving " << scdList.size() << " SCD files to directory " << bkDir;

    for (scd_it = scdList.begin(); scd_it != scdList.end(); ++scd_it)
    {
        try
        {
            bfs::rename(*scd_it, bkDir / bfs::path(*scd_it).filename());
        }
        catch (bfs::filesystem_error& e)
        {
            LOG(WARNING) << "exception in rename file " << *scd_it << ": " << e.what();
        }
    }
}

void MultiDocSummarizationSubManager::DoInsertBuildIndexOfParentKey_(
        const std::string& fileName)
{
    ScdParser parser(UString::UTF_8);
    if (!parser.load(fileName)) return;
    for (ScdParser::iterator doc_iter = parser.begin();
            doc_iter != parser.end(); ++doc_iter)
    {
        if (*doc_iter == NULL)
        {
            LOG(WARNING) << "SCD File not valid.";
            return;
        }
        SCDDocPtr doc = (*doc_iter);
        if (!CheckParentKeyLogFormat(doc, parent_key_ustr_name_))
            continue;
        parent_key_storage_->Insert((*doc)[1].second, (*doc)[0].second);
    }
}

void MultiDocSummarizationSubManager::DoUpdateIndexOfParentKey_(
        const std::string& fileName)
{
    ScdParser parser(UString::UTF_8);
    if (!parser.load(fileName)) return;
    for (ScdParser::iterator doc_iter = parser.begin();
            doc_iter != parser.end(); ++doc_iter)
    {
        if (*doc_iter == NULL)
        {
            LOG(WARNING) << "SCD File not valid.";
            return;
        }
        SCDDocPtr doc = (*doc_iter);
        if (!CheckParentKeyLogFormat(doc, parent_key_ustr_name_))
            continue;
        parent_key_storage_->Update((*doc)[1].second, (*doc)[0].second);
    }
}

void MultiDocSummarizationSubManager::DoDelBuildIndexOfParentKey_(
        const std::string& fileName)
{
    ScdParser parser(UString::UTF_8);
    if (!parser.load(fileName)) return;
    static const UString no_parent;
    for (ScdParser::iterator doc_iter = parser.begin();
            doc_iter != parser.end(); ++doc_iter)
    {
        if (*doc_iter == NULL)
        {
            LOG(WARNING) << "SCD File not valid.";
            return;
        }
        SCDDocPtr doc = (*doc_iter);
        switch (doc->size())
        {
        case 1:
            parent_key_storage_->Delete(no_parent, (*doc)[0].second);
            break;
        case 2:
            parent_key_storage_->Delete((*doc)[1].second, (*doc)[0].second);
            break;
        default:
            break;
        }
    }
}

}
<commit_msg>adjust the summarization policy: when merging all documents into single one, RI will be much slower, so only pure SPLM is used<commit_after>#include "SummarizationSubManager.h"
#include "ParentKeyStorage.h"
#include "SummarizationStorage.h"
#include "CommentCacheStorage.h"
#include "splm.h"

#include <index-manager/IndexManager.h>
#include <document-manager/DocumentManager.h>

#include <common/ScdParser.h>
#include <idmlib/util/idm_analyzer.h>

#include <boost/filesystem.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/algorithm/string.hpp>

#include <glog/logging.h>

#include <iostream>
#include <vector>
#include <algorithm>

using namespace izenelib::ir::indexmanager;
namespace bfs = boost::filesystem;

namespace sf1r
{

static const UString DOCID("DOCID", UString::UTF_8);

bool CheckParentKeyLogFormat(
        const SCDDocPtr& doc,
        const UString& parent_key_name)
{
    if (doc->size() != 2) return false;
    const UString& first = (*doc)[0].first;
    const UString& second = (*doc)[1].first;
    //FIXME case insensitive compare, but it requires extra string conversion,
    //which introduces unnecessary memory fragments
    return (first == DOCID && second == parent_key_name);
}

struct IsParentKeyFilterProperty
{
    const std::string& parent_key_property;

    IsParentKeyFilterProperty(const std::string& property)
        : parent_key_property(property)
    {}

    bool operator()(const QueryFiltering::FilteringType& filterType)
    {
        return boost::iequals(parent_key_property, filterType.property_);
    }
};

MultiDocSummarizationSubManager::MultiDocSummarizationSubManager(
        const std::string& homePath,
        SummarizeConfig schema,
        boost::shared_ptr<DocumentManager> document_manager,
        boost::shared_ptr<IndexManager> index_manager,
        idmlib::util::IDMAnalyzer* analyzer)
    : schema_(schema)
    , parent_key_ustr_name_(schema_.parentKey, UString::UTF_8)
    , document_manager_(document_manager)
    , index_manager_(index_manager)
    , analyzer_(analyzer)
    , comment_cache_storage_(new CommentCacheStorage(homePath + "/comment_cache"))
    , parent_key_storage_(new ParentKeyStorage(homePath, comment_cache_storage_))
    , summarization_storage_(new SummarizationStorage(homePath + "/summarization"))
    , corpus_(new Corpus())
{
    if (!schema_.parentKeyLogPath.empty())
        bfs::create_directories(schema_.parentKeyLogPath);
}

MultiDocSummarizationSubManager::~MultiDocSummarizationSubManager()
{
    delete parent_key_storage_;
    delete summarization_storage_;
    delete comment_cache_storage_;
    delete corpus_;
}

void MultiDocSummarizationSubManager::EvaluateSummarization()
{
    BuildIndexOfParentKey_();

    if (schema_.parentKeyLogPath.empty())
    {
        for (uint32_t i = 1; i <= document_manager_->getMaxDocId(); i++)
        {
            Document doc;
            document_manager_->getDocument(i, doc);
            Document::property_const_iterator kit = doc.findProperty(schema_.foreignKeyPropName);
            if (kit == doc.propertyEnd())
                continue;

            Document::property_const_iterator cit = doc.findProperty(schema_.contentPropName);
            if (cit == doc.propertyEnd())
                continue;

            const UString& key = kit->second.get<UString>();
            const UString& content = cit->second.get<UString>();
            comment_cache_storage_->AppendUpdate(key, i, content);
        }
    }
    else
    {
        for (uint32_t i = 1; i <= document_manager_->getMaxDocId(); i++)
        {
            Document doc;
            document_manager_->getDocument(i, doc);
            Document::property_const_iterator kit = doc.findProperty(schema_.foreignKeyPropName);
            if (kit == doc.propertyEnd())
                continue;

            Document::property_const_iterator cit = doc.findProperty(schema_.contentPropName);
            if (cit == doc.propertyEnd())
                continue;

            const UString& key = kit->second.get<UString>();
            UString parent_key;
            if (!parent_key_storage_->GetParent(key, parent_key))
                continue;

            const UString& content = cit->second.get<UString>();
            comment_cache_storage_->AppendUpdate(parent_key, i, content);
        }
    }
    comment_cache_storage_->Flush();

    CommentCacheStorage::CommentCacheIteratorType commentCacheIt(comment_cache_storage_->comment_cache_db_);
    CommentCacheStorage::CommentCacheIteratorType commentCacheEnd;
    for (; commentCacheIt != commentCacheEnd; ++commentCacheIt)
    {
        const UString& key = commentCacheIt->first;
        Summarization summarization(commentCacheIt->second.first);
        DoEvaluateSummarization_(summarization, key, commentCacheIt->second.second);
    }
    summarization_storage_->Flush();
}

void MultiDocSummarizationSubManager::DoEvaluateSummarization_(
        Summarization& summarization,
        const UString& key,
        const std::vector<UString>& content_list)
{
    if (!summarization_storage_->IsRebuildSummarizeRequired(key, summarization))
        return;

#define MAXDOC 100

    ilplib::langid::Analyzer* langIdAnalyzer = document_manager_->getLangId();
    corpus_->start_new_coll(key);
    corpus_->start_new_doc(); // XXX

    for (std::vector<UString>::const_iterator it = content_list.begin();
            it != content_list.end(); ++it)
    {
        // XXX
        // corpus_->start_new_doc();

        const UString& content = *it;
        UString sentence;
        std::size_t startPos = 0;
        while (std::size_t len = langIdAnalyzer->sentenceLength(content, startPos))
        {
            sentence.assign(content, startPos, len);

            corpus_->start_new_sent(sentence);

            std::vector<UString> word_list;
            analyzer_->GetStringList(sentence, word_list);
            for (std::vector<UString>::const_iterator wit = word_list.begin();
                    wit != word_list.end(); ++wit)
            {
                corpus_->add_word(*wit);
            }

            startPos += len;
        }
    }
    corpus_->start_new_sent();
    corpus_->start_new_doc();
    corpus_->start_new_coll();

    std::map<UString, std::vector<std::pair<double, UString> > > summaries;
//#define DEBUG_SUMMARIZATION
#ifdef DEBUG_SUMMARIZATION
    std::string key_str;
    key.convertString(key_str, UString::UTF_8);
    std::cout << "Begin evaluating: " << key_str << std::endl;
#endif
    //if (content_list.size() < 2000 && corpus_->ntotal() < 100000)
    {
        //SPLM::generateSummary(summaries, *corpus_, SPLM::SPLM_RI);
    }
    //else
    {
        SPLM::generateSummary(summaries, *corpus_, SPLM::SPLM_NONE);
    }
#ifdef DEBUG_SUMMARIZATION
    std::cout << "End evaluating: " << key_str << std::endl;
#endif

    //XXX store the generated summary list
    std::vector<std::pair<double, UString> >& summary_list = summaries[key];
    if (!summary_list.empty())
    {
#ifdef DEBUG_SUMMARIZATION
        for (uint32_t i = 0; i < summary_list.size(); i++)
        {
            std::string sent;
            summary_list[i].second.convertString(sent, UString::UTF_8);
            std::cout << "\t" << sent << std::endl;
        }
#endif
        summarization.insertProperty("overview", summary_list);
    }
    summarization_storage_->Update(key, summarization);

    corpus_->reset();
}

bool MultiDocSummarizationSubManager::GetSummarizationByRawKey(
        const UString& rawKey,
        Summarization& result)
{
    return summarization_storage_->Get(rawKey, result);
}

void MultiDocSummarizationSubManager::AppendSearchFilter(
        std::vector<QueryFiltering::FilteringType>& filtingList)
{
    ///When search filter is based on ParentKey, get its associated values,
    ///and add those values to filter conditions.
    ///The typical situation of this happen when :
    ///SELECT * FROM comments WHERE product_type="foo"
    ///This hook will translate the semantic into:
    ///SELECT * FROM comments WHERE product_id="1" OR product_id="2" ...

    typedef std::vector<QueryFiltering::FilteringType>::iterator IteratorType;
    IteratorType it = std::find_if(filtingList.begin(),
            filtingList.end(), IsParentKeyFilterProperty(schema_.parentKey));
    if (it != filtingList.end())
    {
        const std::vector<PropertyValue>& filterParam = it->values_;
        if (!filterParam.empty())
        {
            try
            {
                const std::string& paramValue = get<std::string>(filterParam[0]);
                UString paramUStr(paramValue, UString::UTF_8);
                std::vector<UString> results;
                if (parent_key_storage_->GetChildren(paramUStr, results))
                {
                    BTreeIndexerManager* pBTreeIndexer = index_manager_->getBTreeIndexer();
                    QueryFiltering::FilteringType filterRule;
                    filterRule.operation_ = QueryFiltering::INCLUDE;
                    filterRule.property_ = schema_.foreignKeyPropName;
                    std::vector<UString>::const_iterator rit = results.begin();
                    for (; rit != results.end(); ++rit)
                    {
                        if (pBTreeIndexer->seek(schema_.foreignKeyPropName, *rit))
                        {
                            ///Protection
                            ///Or else, too many unexisted keys are added
                            PropertyValue v(*rit);
                            filterRule.values_.push_back(v);
                        }
                    }
                    //filterRule.logic_ = QueryFiltering::OR;
                    filtingList.erase(it);
                    //it->logic_ = QueryFiltering::OR;
                    filtingList.push_back(filterRule);
                }
            }
            catch (const boost::bad_get &)
            {
                filtingList.erase(it);
                return;
            }
        }
    }
}

void MultiDocSummarizationSubManager::BuildIndexOfParentKey_()
{
    if (schema_.parentKeyLogPath.empty()) return;
    ScdParser parser(UString::UTF_8);
    std::vector<std::string> scdList;
    static const bfs::directory_iterator kItrEnd;
    for (bfs::directory_iterator itr(schema_.parentKeyLogPath); itr != kItrEnd; ++itr)
    {
        if (bfs::is_regular_file(itr->status()))
        {
            std::string fileName = itr->path().filename().string();
            if (parser.checkSCDFormat(fileName))
            {
                scdList.push_back(itr->path().string());
            }
            else
            {
                LOG(WARNING) << "SCD File not valid " << fileName;
            }
        }
    }

    std::vector<std::string>::const_iterator scd_it = scdList.begin();

    for (; scd_it != scdList.end(); ++scd_it)
    {
        size_t pos = scd_it->rfind("/") + 1;
        string filename = scd_it->substr(pos);

        LOG(INFO) << "Processing SCD file. " << bfs::path(*scd_it).stem();

        switch (parser.checkSCDType(*scd_it))
        {
        case INSERT_SCD:
            DoInsertBuildIndexOfParentKey_(*scd_it);
            LOG(INFO) << "Indexing Finished";
            break;
        case DELETE_SCD:
            DoDelBuildIndexOfParentKey_(*scd_it);
            LOG(INFO) << "Delete Finished";
            break;
        case UPDATE_SCD:
            DoUpdateIndexOfParentKey_(*scd_it);
            LOG(INFO) << "Update Finished";
            break;
        default:
            break;
        }
        parser.load(*scd_it);
    }
    parent_key_storage_->Flush();

    bfs::path bkDir = bfs::path(schema_.parentKeyLogPath) / "backup";
    bfs::create_directory(bkDir);
    LOG(INFO) << "moving " << scdList.size() << " SCD files to directory " << bkDir;

    for (scd_it = scdList.begin(); scd_it != scdList.end(); ++scd_it)
    {
        try
        {
            bfs::rename(*scd_it, bkDir / bfs::path(*scd_it).filename());
        }
        catch (bfs::filesystem_error& e)
        {
            LOG(WARNING) << "exception in rename file " << *scd_it << ": " << e.what();
        }
    }
}

void MultiDocSummarizationSubManager::DoInsertBuildIndexOfParentKey_(
        const std::string& fileName)
{
    ScdParser parser(UString::UTF_8);
    if (!parser.load(fileName)) return;
    for (ScdParser::iterator doc_iter = parser.begin();
            doc_iter != parser.end(); ++doc_iter)
    {
        if (*doc_iter == NULL)
        {
            LOG(WARNING) << "SCD File not valid.";
            return;
        }
        SCDDocPtr doc = (*doc_iter);
        if (!CheckParentKeyLogFormat(doc, parent_key_ustr_name_))
            continue;
        parent_key_storage_->Insert((*doc)[1].second, (*doc)[0].second);
    }
}

void MultiDocSummarizationSubManager::DoUpdateIndexOfParentKey_(
        const std::string& fileName)
{
    ScdParser parser(UString::UTF_8);
    if (!parser.load(fileName)) return;
    for (ScdParser::iterator doc_iter = parser.begin();
            doc_iter != parser.end(); ++doc_iter)
    {
        if (*doc_iter == NULL)
        {
            LOG(WARNING) << "SCD File not valid.";
            return;
        }
        SCDDocPtr doc = (*doc_iter);
        if (!CheckParentKeyLogFormat(doc, parent_key_ustr_name_))
            continue;
        parent_key_storage_->Update((*doc)[1].second, (*doc)[0].second);
    }
}

void MultiDocSummarizationSubManager::DoDelBuildIndexOfParentKey_(
        const std::string& fileName)
{
    ScdParser parser(UString::UTF_8);
    if (!parser.load(fileName)) return;
    static const UString no_parent;
    for (ScdParser::iterator doc_iter = parser.begin();
            doc_iter != parser.end(); ++doc_iter)
    {
        if (*doc_iter == NULL)
        {
            LOG(WARNING) << "SCD File not valid.";
            return;
        }
        SCDDocPtr doc = (*doc_iter);
        switch (doc->size())
        {
        case 1:
            parent_key_storage_->Delete(no_parent, (*doc)[0].second);
            break;
        case 2:
            parent_key_storage_->Delete((*doc)[1].second, (*doc)[0].second);
            break;
        default:
            break;
        }
    }
}

}
<|endoftext|>


<commit_before><commit_msg>Disable external DNS resolutions for in-process tests.<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/ui/ui_test.h"

#include "base/file_path.h"
#include "base/path_service.h"
#include "base/test/test_timeouts.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/ui/npapi_test_helper.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

using npapi_test::kTestCompleteCookie;
using npapi_test::kTestCompleteSuccess;

static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("npapi");

class LayoutPluginTester : public NPAPITesterBase {
 protected:
  LayoutPluginTester() : NPAPITesterBase() {}
};

// Make sure that navigating away from a plugin referenced by JS doesn't
// crash.
TEST_F(LayoutPluginTester, UnloadNoCrash) {
  FilePath path;
  PathService::Get(chrome::DIR_TEST_DATA, &path);
  path = path.AppendASCII("npapi").AppendASCII("layout_test_plugin.html");
  NavigateToURL(net::FilePathToFileURL(path));

  std::wstring title;
  scoped_refptr<TabProxy> tab = GetActiveTab();
  ASSERT_TRUE(tab);
  EXPECT_TRUE(tab->GetTabTitle(&title));
  EXPECT_EQ(L"Layout Test Plugin Test", title);

  ASSERT_TRUE(tab->GoBack());
  EXPECT_TRUE(tab->GetTabTitle(&title));
  EXPECT_NE(L"Layout Test Plugin Test", title);
}

// Tests if a plugin executing a self deleting script using NPN_GetURL
// works without crashing or hanging
// Flaky: http://crbug.com/59327
TEST_F(LayoutPluginTester, DISABLED_SelfDeletePluginGetUrl) {
  const FilePath test_case(FILE_PATH_LITERAL("self_delete_plugin_geturl.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
  WaitForFinish("self_delete_plugin_geturl", "1", url,
                kTestCompleteCookie, kTestCompleteSuccess,
                TestTimeouts::action_max_timeout_ms());
}

// Tests if a plugin executing a self deleting script using Invoke
// works without crashing or hanging
// Flaky. See http://crbug.com/30702
TEST_F(LayoutPluginTester, DISABLED_SelfDeletePluginInvoke) {
  const FilePath test_case(FILE_PATH_LITERAL("self_delete_plugin_invoke.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
  WaitForFinish("self_delete_plugin_invoke", "1", url,
                kTestCompleteCookie, kTestCompleteSuccess,
                TestTimeouts::action_max_timeout_ms());
}

TEST_F(LayoutPluginTester, NPObjectReleasedOnDestruction) {
  const FilePath test_case(
      FILE_PATH_LITERAL("npobject_released_on_destruction.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));

  scoped_refptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(window_proxy);
  ASSERT_TRUE(window_proxy->AppendTab(GURL(chrome::kAboutBlankURL)));

  scoped_refptr<TabProxy> tab_proxy(window_proxy->GetTab(0));
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->Close(true));
}

// Test that a dialog is properly created when a plugin throws an
// exception.  Should be run for in and out of process plugins, but
// the more interesting case is out of process, where we must route
// the exception to the correct renderer.
TEST_F(LayoutPluginTester, NPObjectSetException) {
  const FilePath test_case(FILE_PATH_LITERAL("npobject_set_exception.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
  WaitForFinish("npobject_set_exception", "1", url,
                kTestCompleteCookie, kTestCompleteSuccess,
                TestTimeouts::action_max_timeout_ms());
}
<commit_msg>Reenable LayoutPluginTester.SelfDeletePluginGetUrl<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/test/ui/ui_test.h"

#include "base/file_path.h"
#include "base/path_service.h"
#include "base/test/test_timeouts.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/automation/automation_proxy.h"
#include "chrome/test/automation/tab_proxy.h"
#include "chrome/test/base/ui_test_utils.h"
#include "chrome/test/ui/npapi_test_helper.h"
#include "googleurl/src/gurl.h"
#include "net/base/net_util.h"

using npapi_test::kTestCompleteCookie;
using npapi_test::kTestCompleteSuccess;

static const FilePath::CharType* kTestDir = FILE_PATH_LITERAL("npapi");

class LayoutPluginTester : public NPAPITesterBase {
 protected:
  LayoutPluginTester() : NPAPITesterBase() {}
};

// Make sure that navigating away from a plugin referenced by JS doesn't
// crash.
TEST_F(LayoutPluginTester, UnloadNoCrash) {
  FilePath path;
  PathService::Get(chrome::DIR_TEST_DATA, &path);
  path = path.AppendASCII("npapi").AppendASCII("layout_test_plugin.html");
  NavigateToURL(net::FilePathToFileURL(path));

  std::wstring title;
  scoped_refptr<TabProxy> tab = GetActiveTab();
  ASSERT_TRUE(tab);
  EXPECT_TRUE(tab->GetTabTitle(&title));
  EXPECT_EQ(L"Layout Test Plugin Test", title);

  ASSERT_TRUE(tab->GoBack());
  EXPECT_TRUE(tab->GetTabTitle(&title));
  EXPECT_NE(L"Layout Test Plugin Test", title);
}

// Tests if a plugin executing a self deleting script using NPN_GetURL
// works without crashing or hanging
TEST_F(LayoutPluginTester, SelfDeletePluginGetUrl) {
  const FilePath test_case(FILE_PATH_LITERAL("self_delete_plugin_geturl.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
  WaitForFinish("self_delete_plugin_geturl", "1", url,
                kTestCompleteCookie, kTestCompleteSuccess,
                TestTimeouts::action_max_timeout_ms());
}

// Tests if a plugin executing a self deleting script using Invoke
// works without crashing or hanging
// Flaky. See http://crbug.com/30702
TEST_F(LayoutPluginTester, DISABLED_SelfDeletePluginInvoke) {
  const FilePath test_case(FILE_PATH_LITERAL("self_delete_plugin_invoke.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
  WaitForFinish("self_delete_plugin_invoke", "1", url,
                kTestCompleteCookie, kTestCompleteSuccess,
                TestTimeouts::action_max_timeout_ms());
}

TEST_F(LayoutPluginTester, NPObjectReleasedOnDestruction) {
  const FilePath test_case(
      FILE_PATH_LITERAL("npobject_released_on_destruction.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));

  scoped_refptr<BrowserProxy> window_proxy(automation()->GetBrowserWindow(0));
  ASSERT_TRUE(window_proxy);
  ASSERT_TRUE(window_proxy->AppendTab(GURL(chrome::kAboutBlankURL)));

  scoped_refptr<TabProxy> tab_proxy(window_proxy->GetTab(0));
  ASSERT_TRUE(tab_proxy.get());
  ASSERT_TRUE(tab_proxy->Close(true));
}

// Test that a dialog is properly created when a plugin throws an
// exception.  Should be run for in and out of process plugins, but
// the more interesting case is out of process, where we must route
// the exception to the correct renderer.
TEST_F(LayoutPluginTester, NPObjectSetException) {
  const FilePath test_case(FILE_PATH_LITERAL("npobject_set_exception.html"));
  GURL url = ui_test_utils::GetTestUrl(FilePath(kTestDir), test_case);
  ASSERT_NO_FATAL_FAILURE(NavigateToURL(url));
  WaitForFinish("npobject_set_exception", "1", url,
                kTestCompleteCookie, kTestCompleteSuccess,
                TestTimeouts::action_max_timeout_ms());
}
<|endoftext|>