RE: [ROOT] Problem with Automatic schema evolution?

From: Ruben Shahoyan (Ruben.Shahoyan@cern.ch)
Date: Mon Mar 29 2004 - 00:16:44 MEST


Hi Philippe,

> You found a problem we have with schema evolution when the objects
> are stored non-split and member-wise in a TClonesArray and the base class
> of the object changes.
> A patch will be uploaded shortly to allow the reading of your test1.root
> file in a different session.  You will still be unable to read it back
> in the same session where you read the file test0.root.
> 
Thank you, reading in new version for me is enough.

> On the other hand, I am not sure that you used the feature you intented.
> You are currently using a TObjArray of TClonesArray, this effectively
> disable your ability to split the TClonesArray and remove their ability
> to 'save' on new and deletes (because the TObjArray can not be split and
> hence the TClonesArray are recreated when each entry is read).
> 
The splitting by itself was not an issue in our application, since we 
always read the digits of the entire Detector class (as a collection of
sensor's data of given detector). But I did not realise that in order to
profit from clones new/delete mechanism the branch must be split (now I 
understand why is it so). Following to your suggestion I have changed 
the branch initialization a la
TTree::Branch(Detector,32000,kSplitLev), with splitlev=1

But I noticed that even in this case the TClonesArrays were recreated
at every GetEntry(). I managed to force reusing of arrays only after
setting manually TBranch::SetAutoDelete(kFALSE) for each branch created
by by the command above. At the same time documentation claims that the 
default mode is AutoDelete == kFALSE, but I see in the Branch streamer 
code that in certain situations the streamer itself sets kAutoDelete to 
True. Aparently this happens in my case. I was wondering if this is a
safe operation: to redefine the AutoDelete when it was set by streamer?

Regards,
	Ruben


> Instead of using the line:
>   OutTree->Branch("detBranch","TObjArray",&Detector,32000,kSplitLev);
> you may have intended to use
>   OutTree->Branch(Detector,32000,kSplitLev);
> which would created one branch per TClonesArray.
> To make this syntax more usefull you can also rename the TClonesArray
> (i.e. call SetName on the TClonesArray object).  This name will be
> used as the name of the branch.
> 
> If your intention was to have just one branch, then you can work-around
> the problem completely by either replaceing the TClonesArray by another
> container or by calling clones->BypassStreamer(kFALSE) on each clones.
> 
> Cheers,
> Philippe.
> 
> -----Original Message-----
> From: owner-roottalk@pcroot.cern.ch
> [mailto:owner-roottalk@pcroot.cern.ch]On Behalf Of Ruben Shahoyan
> Sent: Thursday, March 25, 2004 9:00 AM
> To: Rene Brun
> Cc: roottalk@cern.ch
> Subject: Re: [ROOT] Problem with Automatic schema evolution?
> 
> 
> Hello Rene,
> 
> On Thu, 25 Mar 2004, Rene Brun wrote:
> > Could you specify which version of ROOT?
> > In case you use an old version, could you try with 3.10/02 or better
> 4.00/03?
> 
> I am using root3.05/02, but I checked, the same happens in 3.10.
> 
> > Could you send a small tar file with teh strict minimum to reproduce this
> > problem?
> 
> I attached the code to reproduce the problem.
> 
> 1) First you should generate the file with digits of version 1, i.e.
> #define STOREFULLINFO in the TestDigit.h is commented:
> 
> ~/NA60/test > root
>   *******************************************
>   *                                         *
>   *        W E L C O M E  to  R O O T       *
>   *                                         *
>   *   Version   3.05/02  11 February 2003   *
>   *                                         *
>   *  You are welcome to visit our Web site  *
>   *          http://root.cern.ch            *
>   *                                         *
>   *******************************************
> ..
> root [0] .L TestDigit.cxx++
> Info in <TUnixSystem::ACLiC>: creating shared library
> /home/shahoian/NA60/test/./TestDigit_cxx.so
> root [1] TestGen("test0.root"); // THIS WILL GENERATE DIGITS OF VERSION 1
> Event 0
> Col#  0 Row#  18 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> Col# 10 Row#   4 |  Digit# 0 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> Col# 11 Row#   9 |  Digit# 1 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> Col# 12 Row#   1 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> Event 1
> Col# 100 Row#  30 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> Col# 110 Row#  18 |  Digit# 0 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> Col# 111 Row#  30 |  Digit# 1 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> Col# 112 Row#   7 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> Col# 113 Row#  26 |  Digit# 3 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> root [2] .q
> 
> 2) Uncomment #define STOREFULLINFO in the TestDigit.h, read just generated
> digits and store
> them in a new file, as a digits of version 2
> 
> ~/NA60/test > root
> ...
> root [0] .L TestDigit.cxx++
> Info in <TUnixSystem::ACLiC>: creating shared library
> /home/shahoian/NA60/test/./TestDigit_cxx.so
> root [1] TestReadWrite("test0.root","test1.root"); // THIS WILL CONVERT THE
> FILE WITH DIGITS_V1 TO FILE OF DIGITS_V2
> Event 0
> Col#  0 Row#  18 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 10 Row#   4 |  Digit# 0 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 11 Row#   9 |  Digit# 1 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 12 Row#   1 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Event 1
> Col# 100 Row#  30 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 110 Row#  18 |  Digit# 0 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 111 Row#  30 |  Digit# 1 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 112 Row#   7 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 113 Row#  26 |  Digit# 3 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> root [2]
> //
> // as you see, the reading of v1 digits with the code of v2 works fine, we
> recover old values. The problem
> // arises when we try to read just stored digits. If it is done in the same
> root session, we get:
> //
> root [2] TestRead("test1.root")
> Event 0
> Error in <TBuffer::CheckByteCount>: object of class TClonesArray read too
> few bytes: 71 instead of 87
> Warning in <TBuffer::CheckByteCount>: TClonesArray::Streamer() not in sync
> with data on file, fix Streamer()
> Error in <TBuffer::CheckByteCount>: object of class TClonesArray read too
> few bytes: 123 instead of 171
> Warning in <TBuffer::CheckByteCount>: TClonesArray::Streamer() not in sync
> with data on file, fix Streamer()
> Col#  0 Row#  18 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col#  0 Row#   4 |  Digit# 0 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col#  0 Row#   9 |  Digit# 1 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col#  0 Row#   1 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Event 1
> Error in <TBuffer::CheckByteCount>: object of class TClonesArray read too
> few bytes: 71 instead of 87
> Warning in <TBuffer::CheckByteCount>: TClonesArray::Streamer() not in sync
> with data on file, fix Streamer()
> Error in <TBuffer::CheckByteCount>: object of class TClonesArray read too
> few bytes: 149 instead of 213
> Warning in <TBuffer::CheckByteCount>: TClonesArray::Streamer() not in sync
> with data on file, fix Streamer()
> Col#  0 Row#  30 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col#  0 Row#  18 |  Digit# 0 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col#  0 Row#  30 |  Digit# 1 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col#  0 Row#   7 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col#  0 Row#  26 |  Digit# 3 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> root [3] .q
> 
> 3) if the just converted digits are read from new root session, we get:
> ~/NA60/test > root
> root [0] .L TestDigit.cxx++
> root [1] TestRead("test1.root")
> Event 0
> Col#  0 Row#  18 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 10 Row#   4 |  Digit# 0 of Sensor 1 | In Clus#  9, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 11 Row#   1 |  Digit# 1 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 12 Row#  -1 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Event 1
> Col# 100 Row#  30 |  Digit# 0 of Sensor 0 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 110 Row#  18 |  Digit# 0 of Sensor 1 | In Clus# 30, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 111 Row#   7 |  Digit# 1 of Sensor 1 | In Clus# 26, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 112 Row#  -1 |  Digit# 2 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> Col# 113 Row#  -1 |  Digit# 3 of Sensor 1 | In Clus# -1, Track Ptr: (nil) |
> X:  0.0 Y:  0.0 Z:  0.0 E:  0.0
> 
> The data member fI of NaDigit1D class is corrupted: it looks like due to the
> wrong offsets it mixes
> the fCluster member (which in this example should be always -1) and fI.
> 
> Best regards,
>      Ruben
> 
> --
> 
> 
> > Ruben Shahoyan wrote:
> > >
> > > Hello,
> > > we have a following problem with I/O of the objects having streamer
> > > versions:
> > > the base object for na60 digits is
> > >
> > > class NaDigit1D :
> > > public TObject {
> > > ...
> > >  protected:
> > >   Int_t fI;             // Value of the digit
> > >   Int_t fCluster;       // Number of the Cluster to which it is attached
> > >   TArrayI* fTracks;     // Optional array of references on track
> > >   //
> > > #ifdef STOREFULLINFO
> > >   Float_t fXYZE[4];
> > >   ClassDef(NaDigit1D,2) // Base class for 1Dim digits with FULL TRACKING
> INFO
> > > #else
> > >   ClassDef(NaDigit1D,1) // Base class for 1Dim digits
> > > #endif
> > > };
> > >
> > > the #define STOREFULLINFO in the NaDigit1D.h allows us to switch from
> > > version 1 to more complete version 2.
> > >
> > > The default constructor is:
> > > NaDigit1D::NaDigit1D()
> > > {
> > >   fI = -1;
> > >   fCluster = -1;
> > >   fTracks = 0;
> > > #ifdef STOREFULLINFO
> > >   fXYZE[0]=fXYZE[1]=fXYZE[2]=fXYZE[3]=0.0;
> > > #endif
> > >   //
> > > }
> > >
> > > The I/O works fine when I read/rewrite the digits of some version with
> the
> > > code compiled with the corresponding version of the class.
> > >
> > > But we have large amount of data written with the version 1 (i.e. w/o
> > > fXYZE member) which we need to read and store after some processing as a
> > > digits of version 2 (with fXYZE member). The code compiled with
> > > #define STOREFULLINFO reads w/o problem the old digits of version 1,
> > > but when I sotre them again, and try to read them back as a digits of
> > > version 2, they appear to be completely corrupted.
> > >
> > > Here is what I get with gDebug = 1 for reading of the class NaPixDigit,
> > > which derives from NaDigit1D by adding a new member fCol.
> > >
> > > (1) Reading the NaDigit1D of version 1 with the class compiled for
> version 2
> > > ...
> > > ====>Rebuilding TStreamerInfo for class: NaPixDigit, version: 1
> > > ====>Rebuilding TStreamerInfo for class: NaDigit1D, version: 1
> > > StreamerInfo for class: NaDigit1D, version=1
> > >   TObject       BASE            offset=  0 type=66 Basic ROOT object
> > >   Int_t         fI              offset= 12 type= 3 Value of the digit
> > >   Int_t         fCluster        offset= 16 type= 3 Number of the Cluster
> to which it is attached
> > >   TArrayI*      fTracks         offset= 20 type=69 Optional array of
> references on track
> > >    i= 0, TObject         type= 66, offset=  0, len=1, method=0
> > >    i= 1, fI              type=  3, offset= 12, len=1, method=0
> > >    i= 2, fCluster        type=  3, offset= 16, len=1, method=0
> > >    i= 3, fTracks         type= 69, offset= 20, len=1, method=1074526452
> > >
> > > StreamerInfo for class: NaPixDigit, version=1
> > >   NaDigit1D     BASE            offset=  0 type= 0 Base class for 1Dim
> digits
> > >   Int_t         fCol            offset= 40 type= 3 Column of the pixel
> (NaDigit1D::fI is row)
> > >    i= 0, NaDigit1D       type=  0, offset=  0, len=1, method=161037840
> > >    i= 1, fCol            type=  3, offset= 40, len=1, method=0
> > >
> > > ....
> > > root [10] gVerTel->GetSensor(0)->GetDigit(2)->Dump()
> > > ==>Dumping object at:a273f80, name=NaPixDigit, class=NaPixDigit
> > > fCol                          0           Column of the pixel
> (NaDigit1D::fI is row)
> > > fI                            147         Value of the digit
> > > fCluster                      2           Number of the Cluster to which
> it is attached
> > > *fTracks                      ->0         Optional array of references
> on track
> > > fXYZE[4]                      0
> > > fUniqueID                     131185      object unique identifier
> > > fBits                         50331648    bit field status word
> > >
> > > Here everything is correct. Now I store these digits and try to
> > > (2) read them back with the same code of NaDigit1D version 2:
> > >
> > > ====>Rebuilding TStreamerInfo for class: NaPixDigit, version: 1
> > > Creating StreamerInfo for class: NaDigit1D, version: 2
> > >
> > > StreamerInfo for class: NaDigit1D, version=2
> > >   TObject       BASE            offset=  0 type=66 Basic ROOT object
> > >   Int_t         fI              offset= 12 type= 3 Value of the digit
> > >   Int_t         fCluster        offset= 16 type= 3 Number of the Cluster
> to which it is attached
> > >   TArrayI*      fTracks         offset= 20 type=69 Optional array of
> references on track
> > >   Float_t       fXYZE[4]        offset= 24 type=25
> > >    i= 0, TObject         type= 66, offset=  0, len=1, method=0
> > >    i= 1, fI              type= 23, offset= 12, len=2, method=0
> > >    i= 2, fTracks         type= 69, offset= 20, len=1, method=1074526452
> > >    i= 3, fXYZE           type= 25, offset= 24, len=4, method=0
> > >
> > > StreamerInfo for class: NaPixDigit, version=1
> > >   NaDigit1D     BASE            offset=  0 type= 0 Base class for 1Dim
> digits
> > >   Int_t         fCol            offset= 40 type= 3 Column of the pixel
> (NaDigit1D::fI is row)
> > >    i= 0, NaDigit1D       type=  0, offset=  0, len=1, method=160981416
> > >    i= 1, fCol            type=  3, offset= 40, len=1, method=0
> > >
> > > ...
> > > root [9] gVerTel->GetSensor(0)->GetDigit(2)->Dump()
> > > ==>Dumping object at:a5c2f38, name=NaPixDigit, class=NaPixDigit
> > >
> > > fCol                          0           Column of the pixel
> (NaDigit1D::fI is row)
> > > fI                            178         Value of the digit
> > > fCluster                      185         Number of the Cluster to which
> it is attached
> > > *fTracks                      ->0         Optional array of references
> on track
> > > fXYZE[4]                      0
> > > fUniqueID                     131185      object unique identifier
> > > fBits                         50331648    bit field status word
> > >
> > > The same digit now has completely different values, and the StreamerInfo
> > > also looks different: in the output (1) it had a table entry for
> > > i= 2, fCluster        type=  3, offset= 16, len=1, method=0
> > >
> > > while in the output (2) it has disappeared, which apparently leads to
> > > misalignment during the reading.
> > >
> > > Have I done something wrong or there is a problem in the schema
> evolution?
> > >
> > > Ruben Shahoyan
> >
> 
> 



This archive was generated by hypermail 2b29 : Sun Jan 02 2005 - 05:50:07 MET