Logo ROOT  
Reference Guide
Loading...
Searching...
No Matches
TKey.cxx
Go to the documentation of this file.
1// @(#)root/io:$Id$
2// Author: Rene Brun 28/12/94
3
4/*************************************************************************
5 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12/**
13\class TKey
14\ingroup io_files
15
16 Book space in a file, create I/O buffers, to fill them, (un)compress them.
17
18 The TKey class includes functions to book space in a file, to create I/O
19 buffers, to fill these buffers, to compress/uncompress data buffers.
20 Before saving (making persistent) an object in a file, a key must
21 be created. The key structure contains all the information to
22 uniquely identify a persistent object in a file.
23 | Data Member | Explanation |
24 |-------------|-------------|
25 | fNbytes | Number of bytes for the compressed object and key. |
26 | fObjlen | Length of uncompressed object. |
27 | fDatime | Date/Time when the object was written. |
28 | fKeylen | Number of bytes for the key structure. |
29 | fCycle | Cycle number of the object. |
30 | fSeekKey | Address of the object on file (points to fNbytes). This is a redundant information used to cross-check the data base integrity. |
31 | fSeekPdir | Pointer to the directory supporting this object.|
32 | fClassName | Object class name. |
33 | fName | Name of the object. |
34 | fTitle | Title of the object. |
35
36 In the 16 highest bits of fSeekPdir is encoded a pid offset. This
37 offset is to be added to the pid index stored in the TRef object
38 and the referenced TObject.
39
40 The TKey class is used by ROOT to:
41 - Write an object in the current directory
42 - Write a new ntuple buffer
43
44 The structure of a file is shown in TFile::TFile.
45 The structure of a directory is shown in TDirectoryFile::TDirectoryFile.
46 The TKey class is used by the TBasket class.
47 See also TTree.
48*/
49
50#include <atomic>
51#include <iostream>
52#include <limits>
53
54#include "TROOT.h"
55#include "TClass.h"
56#include "TDirectoryFile.h"
57#include "TFile.h"
58#include "TKey.h"
59#include "TBufferFile.h"
60#include "TFree.h"
61#include "TBrowser.h"
62#include "Bytes.h"
63#include "TInterpreter.h"
64#include "TError.h"
66#include "TSchemaRuleSet.h"
67#include "ThreadLocalStorage.h"
68
69#include "RZip.h"
70
71const Int_t kTitleMax = 32000;
72
73#if !defined(_MSC_VER) || (_MSC_VER>1300)
74const ULong64_t kPidOffsetMask = 0xffffffffffffULL;
75#else
76const ULong64_t kPidOffsetMask = 0xffffffffffffUL;
77#endif
79
80const static TString gTDirectoryString("TDirectory");
81std::atomic<UInt_t> keyAbsNumber{0};
82
83
84////////////////////////////////////////////////////////////////////////////////
85/// TKey default constructor.
86
88{
89 Build(0, "", 0);
90
91 fKeylen = Sizeof();
92
94}
95
96////////////////////////////////////////////////////////////////////////////////
97/// TKey default constructor.
98
100{
101 Build(motherDir, "", 0);
102
103 fKeylen = Sizeof();
104
106}
107
108////////////////////////////////////////////////////////////////////////////////
109/// Copy a TKey from its original directory to the new 'motherDir'
110
111TKey::TKey(TDirectory* motherDir, const TKey &orig, UShort_t pidOffset) : TNamed(), fDatime((UInt_t)0)
112{
113 fMotherDir = motherDir;
114
115 fPidOffset = orig.fPidOffset + pidOffset;
116 fNbytes = orig.fNbytes;
117 fObjlen = orig.fObjlen;
118 fClassName = orig.fClassName;
119 fName = orig.fName;
120 fTitle = orig.fTitle;
121
122 fCycle = fMotherDir->AppendKey(this);
123 fSeekPdir = 0;
124 fSeekKey = 0;
125 fLeft = 0;
126
128 Long64_t filepos = GetFile()->GetEND();
129 if (filepos > TFile::kStartBigFile || fPidOffset) fVersion += 1000;
130
131 fKeylen = Sizeof(); // fVersion must be set.
132
133 UInt_t bufferDecOffset = 0;
134 UInt_t bufferIncOffset = 0;
135 UInt_t alloc = fNbytes + sizeof(Int_t); // The extra Int_t is for any free space information.
136 if (fKeylen < orig.fKeylen) {
137 bufferDecOffset = orig.fKeylen - fKeylen;
138 fNbytes -= bufferDecOffset;
139 } else if (fKeylen > orig.fKeylen) {
140 bufferIncOffset = fKeylen - orig.fKeylen;
141 alloc += bufferIncOffset;
142 fNbytes += bufferIncOffset;
143 }
144
146 fBuffer = fBufferRef->Buffer();
147
148 // Steal the data from the old key.
149
150 TFile* f = orig.GetFile();
151 if (f) {
152 Int_t nsize = orig.fNbytes;
153 f->Seek(orig.fSeekKey);
154 if( f->ReadBuffer(fBuffer+bufferIncOffset,nsize) )
155 {
156 Error("ReadFile", "Failed to read data.");
157 return;
158 }
159 if (gDebug) {
160 std::cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<std::endl;
161 }
162 }
163 fBuffer += bufferDecOffset; // Reset the buffer to be appropriate for this key.
164 Int_t nout = fNbytes - fKeylen;
165 Create(nout);
166 fBufferRef->SetBufferOffset(bufferDecOffset);
167 Streamer(*fBufferRef); //write key itself again
168}
169
170////////////////////////////////////////////////////////////////////////////////
171/// Create a TKey object to read keys.
172/// Constructor called by TDirectoryFile::ReadKeys and by TFile::TFile.
173/// A TKey object is created to read the keys structure itself.
174
175TKey::TKey(Long64_t pointer, Int_t nbytes, TDirectory* motherDir) : TNamed()
176{
177 Build(motherDir, "", pointer);
178
179 fSeekKey = pointer;
180 fNbytes = nbytes;
181 fBuffer = new char[nbytes];
183}
184
185////////////////////////////////////////////////////////////////////////////////
186/// Create a TKey object with the specified name, title for the given class.
187///
188/// WARNING: in name avoid special characters like '^','$','.' that are used
189/// by the regular expression parser (see TRegexp).
190
191TKey::TKey(const char *name, const char *title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
192 : TNamed(name,title)
193{
194 Build(motherDir, cl->GetName(), -1);
195
196 fKeylen = Sizeof();
197 fObjlen = nbytes;
198 Create(nbytes);
199}
200
201////////////////////////////////////////////////////////////////////////////////
202/// Create a TKey object with the specified name, title for the given class.
203///
204/// WARNING: in name avoid special characters like '^','$','.' that are used
205/// by the regular expression parser (see TRegexp).
206
207TKey::TKey(const TString &name, const TString &title, const TClass *cl, Int_t nbytes, TDirectory* motherDir)
208 : TNamed(name,title)
209{
210 Build(motherDir, cl->GetName(), -1);
211
212 fKeylen = Sizeof();
213 fObjlen = nbytes;
214 Create(nbytes);
215}
216
217////////////////////////////////////////////////////////////////////////////////
218/// Create a TKey object for a TObject* and fill output buffer
219///
220/// WARNING: in name avoid special characters like '^','$','.' that are used
221/// by the regular expression parser (see TRegexp).
222
223TKey::TKey(const TObject *obj, const char *name, Int_t bufsize, TDirectory* motherDir)
224 : TNamed(name, obj->GetTitle())
225{
226 R__ASSERT(obj);
227
228 if (!obj->IsA()->HasDefaultConstructor()) {
229 Warning("TKey", "since %s has no public constructor\n"
230 "\twhich can be called without argument, objects of this class\n"
231 "\tcan not be read with the current library. You will need to\n"
232 "\tadd a default constructor before attempting to read it.",
233 obj->ClassName());
234 }
235
236 Build(motherDir, obj->ClassName(), -1);
237
238 Int_t lbuf, nout, noutot, bufmax, nzip;
239 fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
240 fBufferRef->SetParent(GetFile());
241 fCycle = fMotherDir->AppendKey(this);
242
243 Streamer(*fBufferRef); //write key itself
244 fKeylen = fBufferRef->Length();
245 fBufferRef->MapObject(obj); //register obj in map in case of self reference
246 ((TObject*)obj)->Streamer(*fBufferRef); //write object
247 lbuf = fBufferRef->Length();
248 fObjlen = lbuf - fKeylen;
249
250 Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
252 if (cxlevel > 0 && fObjlen > 256) {
253 Int_t nbuffers = 1 + (fObjlen - 1)/kMAXZIPBUF;
254 Int_t buflen = std::max(512,fKeylen + fObjlen + 9*nbuffers + 28); //add 28 bytes in case object is placed in a deleted gap
255 fBuffer = new char[buflen];
256 char *objbuf = fBufferRef->Buffer() + fKeylen;
257 char *bufcur = &fBuffer[fKeylen];
258 noutot = 0;
259 nzip = 0;
260 for (Int_t i = 0; i < nbuffers; ++i) {
261 if (i == nbuffers - 1) bufmax = fObjlen - nzip;
262 else bufmax = kMAXZIPBUF;
263 R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
264 if (nout == 0 || nout >= fObjlen) { //this happens when the buffer cannot be compressed
265 delete[] fBuffer;
266 bufcur = nullptr;
267 fBuffer = fBufferRef->Buffer();
269 fBufferRef->SetBufferOffset(0);
270 Streamer(*fBufferRef); //write key itself again
271 return;
272 }
273 bufcur += nout;
274 noutot += nout;
275 objbuf += kMAXZIPBUF;
276 nzip += kMAXZIPBUF;
277 }
278 Create(noutot);
279 fBufferRef->SetBufferOffset(0);
280 Streamer(*fBufferRef); //write key itself again
281 memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
282 delete fBufferRef; fBufferRef = 0;
283 } else {
284 fBuffer = fBufferRef->Buffer();
286 fBufferRef->SetBufferOffset(0);
287 Streamer(*fBufferRef); //write key itself again
288 }
289}
290
291////////////////////////////////////////////////////////////////////////////////
292/// Create a TKey object for any object obj of class cl d and fill
293/// output buffer.
294///
295/// WARNING: in name avoid special characters like '^','$','.' that are used
296/// by the regular expression parser (see TRegexp).
297
298TKey::TKey(const void *obj, const TClass *cl, const char *name, Int_t bufsize, TDirectory *motherDir) : TNamed(name, "")
299{
300 R__ASSERT(obj && cl);
301
302 if (!cl->HasDefaultConstructor()) {
303 Warning("TKey", "since %s has no public constructor\n"
304 "\twhich can be called without argument, objects of this class\n"
305 "\tcan not be read with the current library. You will need to\n"
306 "\tadd a default constructor before attempting to read it.",
307 cl->GetName());
308 }
309
310 TClass *clActual = cl->GetActualClass(obj);
311 const void* actualStart;
312 if (clActual) {
313 const char *temp = (const char*) obj;
314 // clActual->GetStreamerInfo();
315 Int_t offset = (cl != clActual) ?
316 clActual->GetBaseClassOffset(cl) : 0;
317 temp -= offset;
318 actualStart = temp;
319 } else {
320 // We could not determine the real type of this object,
321 // let's assume it is the one given by the caller.
322 clActual = const_cast<TClass*>(cl);
323 actualStart = obj;
324 }
325
326 Build(motherDir, clActual->GetName(), -1);
327
328 fBufferRef = new TBufferFile(TBuffer::kWrite, bufsize);
329 fBufferRef->SetParent(GetFile());
330
331 Streamer(*fBufferRef); //write key itself
332 fKeylen = fBufferRef->Length();
333
334 Int_t lbuf, nout, noutot, bufmax, nzip;
335
336 fBufferRef->MapObject(actualStart,clActual); //register obj in map in case of self reference
337 clActual->Streamer((void*)actualStart, *fBufferRef); //write object
338 lbuf = fBufferRef->Length();
339 fObjlen = lbuf - fKeylen;
340
341 // Append to mother directory only after the call to Streamer() was
342 // successful (and didn't throw).
343 fCycle = fMotherDir->AppendKey(this);
344
345 Int_t cxlevel = GetFile() ? GetFile()->GetCompressionLevel() : 0;
347 if (cxlevel > 0 && fObjlen > 256) {
348 Int_t nbuffers = 1 + (fObjlen - 1)/kMAXZIPBUF;
349 Int_t buflen = std::max(512,fKeylen + fObjlen + 9*nbuffers + 28); //add 28 bytes in case object is placed in a deleted gap
350 fBuffer = new char[buflen];
351 char *objbuf = fBufferRef->Buffer() + fKeylen;
352 char *bufcur = &fBuffer[fKeylen];
353 noutot = 0;
354 nzip = 0;
355 for (Int_t i = 0; i < nbuffers; ++i) {
356 if (i == nbuffers - 1) bufmax = fObjlen - nzip;
357 else bufmax = kMAXZIPBUF;
358 R__zipMultipleAlgorithm(cxlevel, &bufmax, objbuf, &bufmax, bufcur, &nout, cxAlgorithm);
359 if (nout == 0 || nout >= fObjlen) { //this happens when the buffer cannot be compressed
360 delete[] fBuffer;
361 bufcur = nullptr;
362 fBuffer = fBufferRef->Buffer();
364 fBufferRef->SetBufferOffset(0);
365 Streamer(*fBufferRef); //write key itself again
366 return;
367 }
368 bufcur += nout;
369 noutot += nout;
370 objbuf += kMAXZIPBUF;
371 nzip += kMAXZIPBUF;
372 }
373 Create(noutot);
374 fBufferRef->SetBufferOffset(0);
375 Streamer(*fBufferRef); //write key itself again
376 memcpy(fBuffer,fBufferRef->Buffer(),fKeylen);
377 delete fBufferRef; fBufferRef = 0;
378 } else {
379 fBuffer = fBufferRef->Buffer();
381 fBufferRef->SetBufferOffset(0);
382 Streamer(*fBufferRef); //write key itself again
383 }
384}
385
386/// Core of uncompressing the key payload. Returns number of bytes uncompressed.
387/// We expect that the compressedBuffer contains the entire key (key header + payload).
388/// The target buffer must have space for at least fObjLen bytes.
389/// Lastly, the object length must be larger than the key payload, i.e. we already know that
390/// we have a compressed payload.
391Int_t TKey::UnzipBuffer(char *targetBuffer, const char *compressedBuffer) const
392{
393 auto objbuf = reinterpret_cast<unsigned char *>(targetBuffer) + fKeylen;
394 auto bufcur = reinterpret_cast<const unsigned char *>(&compressedBuffer[fKeylen]);
395 Int_t nin, nout = 0, nbuf;
396 Int_t noutot = 0;
397 Int_t nbytesRemain = fNbytes - fKeylen;
398 Int_t objlenRemain = fObjlen;
399 while (nbytesRemain >= ROOT::Internal::kZipHeaderSize) {
400 Int_t hc = R__unzip_header(&nin, bufcur, &nbuf);
401 if ((hc != 0) || (nin > nbytesRemain) || (nbuf > objlenRemain))
402 return 0;
403 R__unzip(&nin, bufcur, &nbuf, objbuf, &nout);
404 if (!nout)
405 return 0;
406 noutot += nout;
407 if (noutot >= fObjlen)
408 break;
409 bufcur += nin;
410 objbuf += nout;
411 nbytesRemain -= nin;
412 objlenRemain -= nout;
413 }
414 return nout;
415}
416
417////////////////////////////////////////////////////////////////////////////////
418/// Method used in all TKey constructor to initialize basic data fields.
419///
420/// The member filepos is used to calculate correct version number of key
421/// if filepos==-1, end of file position is used.
422
423void TKey::Build(TDirectory* motherDir, const char* classname, Long64_t filepos)
424{
425 fMotherDir = motherDir;
426
427 fPidOffset = 0;
428 fNbytes = 0;
429 fBuffer = 0;
430 fKeylen = 0;
431 fObjlen = 0;
432 fBufferRef = 0;
433 fCycle = 0;
434 fSeekPdir = 0;
435 fSeekKey = 0;
436 fLeft = 0;
437
438 fClassName = classname;
439 //the following test required for forward and backward compatibility
440 if (fClassName == "TDirectoryFile") SetBit(kIsDirectoryFile);
441
443
444 if ((filepos==-1) && GetFile()) filepos = GetFile()->GetEND();
445 if (filepos > TFile::kStartBigFile) fVersion += 1000;
446
447 if (fTitle.Length() > kTitleMax) fTitle.Resize(kTitleMax);
448
451}
452
453////////////////////////////////////////////////////////////////////////////////
454/// Read object from disk and call its Browse() method.
455///
456/// If object with same name already exist in memory delete it (like
457/// TDirectoryFile::Get() is doing), except when the key references a
458/// folder in which case we don't want to re-read the folder object
459/// since it might contain new objects not yet saved.
460
462{
463 if (fMotherDir==0) return;
464
466
467 void* obj = fMotherDir->GetList()->FindObject(GetName());
468 if (obj && objcl->IsTObject()) {
469 TObject *tobj = (TObject*) objcl->DynamicCast(TObject::Class(), obj);
470 if (!tobj->IsFolder()) {
471 if (tobj->InheritsFrom(TCollection::Class()))
472 tobj->Delete(); // delete also collection elements
473 delete tobj;
474 obj = 0;
475 }
476 }
477
478 if (!obj)
479 obj = ReadObj();
480
481 if (b && obj) {
482 objcl->Browse(obj,b);
483 b->SetRefreshFlag(kTRUE);
484 }
485}
486
487////////////////////////////////////////////////////////////////////////////////
488/// Create a TKey object of specified size.
489///
490/// If externFile!=0, key will be allocated in specified file, otherwise file
491/// of mother directory will be used.
492
493void TKey::Create(Int_t nbytes, TFile* externFile)
494{
496
497 TFile *f = externFile;
498 if (!f) f = GetFile();
499 if (!f) {
500 Error("Create","Cannot create key without file");
501 return;
502 }
503
504 Int_t nsize = nbytes + fKeylen;
505 TList *lfree = f->GetListOfFree();
506 TFree *f1 = (TFree*)lfree->First();
507//*-*-------------------find free segment
508//*-* =================
509 TFree *bestfree = f1->GetBestFree(lfree,nsize);
510 if (bestfree == 0) {
511 Error("Create","Cannot allocate %d bytes for ID = %s Title = %s",
512 nsize,GetName(),GetTitle());
513 return;
514 }
515
516 if (f->TestBit(TFile::kReproducible))
518
519 fDatime.Set();
520 fSeekKey = bestfree->GetFirst();
521//*-*----------------- Case Add at the end of the file
522 if (fSeekKey >= f->GetEND()) {
523 f->SetEND(fSeekKey+nsize);
524 bestfree->SetFirst(fSeekKey+nsize);
525 if (f->GetEND() > bestfree->GetLast()) {
526 bestfree->SetLast(bestfree->GetLast() + 1000000000);
527 }
528 fLeft = -1;
529 if (!fBuffer) fBuffer = new char[nsize];
530 } else {
531 fLeft = Int_t(bestfree->GetLast() - fSeekKey - nsize + 1);
532 }
533//*-*----------------- Case where new object fills exactly a deleted gap
534 fNbytes = nsize;
535 if (fLeft == 0) {
536 if (!fBuffer) {
537 fBuffer = new char[nsize];
538 }
539 lfree->Remove(bestfree);
540 delete bestfree;
541 }
542//*-*----------------- Case where new object is placed in a deleted gap larger than itself
543 if (fLeft > 0) { // found a bigger segment
544 if (!fBuffer) {
545 fBuffer = new char[nsize+sizeof(Int_t)];
546 }
547 char *buffer = fBuffer+nsize;
548 Int_t nbytesleft = -fLeft; // set header of remaining record
549 tobuf(buffer, nbytesleft);
550 bestfree->SetFirst(fSeekKey+nsize);
551 }
552
553 fSeekPdir = externFile ? externFile->GetSeekDir() : fMotherDir->GetSeekDir();
554}
555
556////////////////////////////////////////////////////////////////////////////////
557/// TKey default destructor.
558
560{
561 if (fMotherDir && fMotherDir->GetListOfKeys())
562 fMotherDir->GetListOfKeys()->Remove(this);
564}
565
566////////////////////////////////////////////////////////////////////////////////
567/// Delete an object from the file.
568///
569/// Note: the key is not deleted. You still have to call "delete key".
570/// This is different from the behaviour of TObject::Delete()!
571
573{
575 // TDirectoryFile assumes that its location on file never change (for example updates are partial)
576 // and never checks if the space might have been released and thus over-write any data that might
577 // have been written there.
578 if (option && option[0] == 'v')
579 printf("Rejected attempt to delete TDirectoryFile key: %s at address %lld, nbytes = %d\n",
581 return;
582 }
583 if (option && option[0] == 'v') printf("Deleting key: %s at address %lld, nbytes = %d\n",GetName(),fSeekKey,fNbytes);
584 Long64_t first = fSeekKey;
585 Long64_t last = fSeekKey + fNbytes -1;
586 if (GetFile()) GetFile()->MakeFree(first, last); // release space used by this key
587 fMotherDir->GetListOfKeys()->Remove(this);
588}
589
590////////////////////////////////////////////////////////////////////////////////
591/// Delete key buffer(s).
592
594{
595 if (fBufferRef) {
596 delete fBufferRef;
597 fBufferRef = 0;
598 } else {
599 // We only need to delete fBuffer if fBufferRef is zero because
600 // if fBufferRef exists, we delegate ownership of fBuffer to fBufferRef.
601 if (fBuffer) {
602 delete [] fBuffer;
603 }
604 }
605 fBuffer = 0;
606}
607
608////////////////////////////////////////////////////////////////////////////////
609/// Return cycle number associated to this key.
610
612{
613 return ((fCycle >0) ? fCycle : -fCycle);
614}
615
616////////////////////////////////////////////////////////////////////////////////
617/// Returns file to which key belong.
618
620{
621 return fMotherDir!=0 ? fMotherDir->GetFile() : gFile;
622}
623
624////////////////////////////////////////////////////////////////////////////////
625/// Returns the "KEEP" status.
626
628{
629 return ((fCycle >0) ? 0 : 1);
630}
631
632////////////////////////////////////////////////////////////////////////////////
633/// Encode key header into output buffer.
634
635void TKey::FillBuffer(char *&buffer)
636{
637 tobuf(buffer, fNbytes);
638 Version_t version = fVersion;
639 tobuf(buffer, version);
640
641 tobuf(buffer, fObjlen);
643 TDatime((UInt_t) 1).FillBuffer(buffer);
644 else
645 fDatime.FillBuffer(buffer);
646 tobuf(buffer, fKeylen);
647 tobuf(buffer, fCycle);
648 if (fVersion > 1000) {
649 tobuf(buffer, fSeekKey);
650
651 // We currently store in the 16 highest bit of fSeekPdir the value of
652 // fPidOffset. This offset is used when a key (or basket) is transferred from one
653 // file to the other. In this case the TRef and TObject might have stored a
654 // pid index (to retrieve TProcessIDs) which refered to their order on the original
655 // file, the fPidOffset is to be added to those values to correctly find the
656 // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
657 // and need to be zero for new key/basket.
659 tobuf(buffer, pdir);
660 } else {
661 tobuf(buffer, (Int_t)fSeekKey);
662 tobuf(buffer, (Int_t)fSeekPdir);
663 }
665 // We want to record "TDirectory" instead of TDirectoryFile so that the file can be read by ancient version of ROOT.
666 gTDirectoryString.FillBuffer(buffer);
667 } else {
668 fClassName.FillBuffer(buffer);
669 }
670 fName.FillBuffer(buffer);
671 fTitle.FillBuffer(buffer);
672}
673
674////////////////////////////////////////////////////////////////////////////////
675/// Increment fPidOffset by 'offset'.
676///
677/// This offset is used when a key (or basket) is transferred from one file to
678/// the other. In this case the TRef and TObject might have stored a pid
679/// index (to retrieve TProcessIDs) which refered to their order on the
680/// original file, the fPidOffset is to be added to those values to correctly
681/// find the TProcessID. This fPidOffset needs to be increment if the
682/// key/basket is copied and need to be zero for new key/basket.
683
685{
686 fPidOffset += offset;
687 if (fPidOffset) {
688 // We currently store fPidOffset in the 16 highest bit of fSeekPdir, which
689 // need to be store as a 64 bit integer. So we require this key to be
690 // a 'large file' key.
691 if (fVersion<1000) fVersion += 1000;
692 }
693}
694
695////////////////////////////////////////////////////////////////////////////////
696/// Check if object referenced by the key is a folder.
697
699{
700 Bool_t ret = kFALSE;
701
702 TClass *classPtr = TClass::GetClass((const char *) fClassName);
703 if (classPtr && classPtr->GetState() > TClass::kEmulated && classPtr->IsTObject()) {
704 TObject *obj = (TObject *) classPtr->DynamicCast(TObject::Class(), classPtr->New(TClass::kDummyNew));
705 if (obj) {
706 ret = obj->IsFolder();
707 delete obj;
708 }
709 }
710
711 return ret;
712}
713
714////////////////////////////////////////////////////////////////////////////////
715/// Set the "KEEP" status.
716///
717/// When the KEEP flag is set to 1 the object cannot be purged.
718
720{
721 if (fCycle >0) fCycle = -fCycle;
722}
723
724////////////////////////////////////////////////////////////////////////////////
725/// List Key contents.
726/// Add indicator of whether it is the current item or a backup copy.
727
728void TKey::ls(Bool_t current) const
729{
731 std::cout <<"KEY: "<<fClassName<<"\t"<<GetName()<<";"<<GetCycle()<<"\t"<<GetTitle();
732 std::cout << (current ? " [current cycle]" : " [backup cycle]");
733 std::cout <<std::endl;
734}
735
736////////////////////////////////////////////////////////////////////////////////
737/// List Key contents.
738
739void TKey::ls(Option_t *) const
740{
742 std::cout <<"KEY: "<<fClassName<<"\t"<<GetName()<<";"<<GetCycle()<<"\t"<<GetTitle()<<std::endl;
743}
744
745////////////////////////////////////////////////////////////////////////////////
746/// Print key contents.
747
749{
750 printf("TKey Name = %s, Title = %s, Cycle = %d\n",GetName(),GetTitle(),GetCycle());
751}
752
753////////////////////////////////////////////////////////////////////////////////
754/// To read a TObject* from the file.
755///
756/// The object associated to this key is read from the file into memory
757/// Once the key structure is read (via Streamer) the class identifier
758/// of the object is known.
759/// Using the class identifier we find the TClass object for this class.
760/// A TClass object contains a full description (i.e. dictionary) of the
761/// associated class. In particular the TClass object can create a new
762/// object of the class type it describes. This new object now calls its
763/// Streamer function to rebuilt itself.
764///
765/// Use TKey::ReadObjectAny to read any object non-derived from TObject
766///
767/// ### Note
768/// A C style cast can only be used in the case where the final class
769/// of this object derives from TObject as a first inheritance, otherwise
770/// one must use a dynamic_cast.
771///
772/// #### Example1: simplified case
773/// ~~~{.cpp}
774/// class MyClass : public TObject, public AnotherClass
775/// ~~~
776/// then on return, one get away with using:
777/// ~~~{.cpp}
778/// MyClass *obj = (MyClass*)key->ReadObj();
779/// ~~~
780///
781/// #### Example2: Usual case (recommended unless performance is critical)
782/// ~~~{.cpp}
783/// MyClass *obj = dynamic_cast<MyClass*>(key->ReadObj());
784/// ~~~
785/// which support also the more complex inheritance like:
786/// ~~~{.cpp}
787/// class MyClass : public AnotherClass, public TObject
788/// ~~~
789///
790/// Of course, `dynamic_cast<>` can also be used in the example 1.
791
793{
794 TClass *cl = TClass::GetClass(fClassName.Data());
795 if (!cl) {
796 Error("ReadObj", "Unknown class %s", fClassName.Data());
797 return 0;
798 }
799 if (!cl->IsTObject()) {
800 // in principle user should call TKey::ReadObjectAny!
801 return (TObject*)ReadObjectAny(0);
802 }
803
805 if (!bufferRef.Buffer()) {
806 Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
807 return 0;
808 }
809 if (GetFile()==0) return 0;
810 bufferRef.SetParent(GetFile());
811 bufferRef.SetPidOffset(fPidOffset);
812
813 std::unique_ptr<char []> compressedBuffer;
814 auto storeBuffer = fBuffer;
815 if (fObjlen > fNbytes-fKeylen) {
816 compressedBuffer.reset(new char[fNbytes]);
817 fBuffer = compressedBuffer.get();
818 if( !ReadFile() ) //Read object structure from file
819 {
820 fBuffer = 0;
821 return 0;
822 }
823 memcpy(bufferRef.Buffer(),fBuffer,fKeylen);
824 } else {
825 fBuffer = bufferRef.Buffer();
826 if( !ReadFile() ) { //Read object structure from file
827
828 fBuffer = 0;
829 return 0;
830 }
831 }
832 fBuffer = storeBuffer;
833
834 // get version of key
835 bufferRef.SetBufferOffset(sizeof(fNbytes));
836 Version_t kvers = bufferRef.ReadVersion();
837
838 bufferRef.SetBufferOffset(fKeylen);
839 TObject *tobj = 0;
840 // Create an instance of this class
841
842 char *pobj = (char*)cl->New();
843 if (!pobj) {
844 Error("ReadObj", "Cannot create new object of class %s", fClassName.Data());
845 return 0;
846 }
847 Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
848 if (baseOffset==-1) {
849 // cl does not inherit from TObject.
850 // Since this is not possible yet, the only reason we could reach this code
851 // is because something is screw up in the ROOT code.
852 Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
853 fClassName.Data());
854 }
855 tobj = (TObject*)(pobj+baseOffset);
856 if (kvers > 1)
857 bufferRef.MapObject(pobj,cl); //register obj in map to handle self reference
858
859 if (fObjlen > fNbytes-fKeylen) {
860 Int_t nout = UnzipBuffer(bufferRef.Buffer(), compressedBuffer.get());
861 compressedBuffer.reset(nullptr);
862 if (nout) {
863 tobj->Streamer(bufferRef); //does not work with example 2 above
864 } else {
865 // Even-though we have a TObject, if the class is emulated the virtual
866 // table may not be 'right', so let's go via the TClass.
867 cl->Destructor(pobj);
868 return nullptr;
869 }
870 } else {
871 tobj->Streamer(bufferRef);
872 }
873
874 if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
875
877 TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
878 dir->SetName(GetName());
879 dir->SetTitle(GetTitle());
880 dir->SetMother(fMotherDir);
881 fMotherDir->Append(dir);
882 }
883
884 // Append the object to the directory if requested:
885 {
887 if (addfunc) {
888 addfunc(pobj, fMotherDir);
889 }
890 }
891
892 return tobj;
893}
894
895////////////////////////////////////////////////////////////////////////////////
896/// To read a TObject* from bufferRead.
897///
898/// This function is identical to TKey::ReadObj, but it reads directly from
899/// bufferRead instead of reading from a file.
900/// The object associated to this key is read from the buffer into memory
901/// Using the class identifier we find the TClass object for this class.
902/// A TClass object contains a full description (i.e. dictionary) of the
903/// associated class. In particular the TClass object can create a new
904/// object of the class type it describes. This new object now calls its
905/// Streamer function to rebuilt itself.
906///
907/// ### Note
908/// This function is called only internally by ROOT classes.
909/// Although being public it is not supposed to be used outside ROOT.
910/// If used, you must make sure that the bufferRead is large enough to
911/// accommodate the object being read.
912
914{
915
916 TClass *cl = TClass::GetClass(fClassName.Data());
917 if (!cl) {
918 Error("ReadObjWithBuffer", "Unknown class %s", fClassName.Data());
919 return 0;
920 }
921 if (!cl->IsTObject()) {
922 // in principle user should call TKey::ReadObjectAny!
923 return (TObject*)ReadObjectAny(0);
924 }
925
927 if (!bufferRef.Buffer()) {
928 Error("ReadObjWithBuffer", "Cannot allocate buffer: fObjlen = %d", fObjlen);
929 return 0;
930 }
931 if (GetFile()==0) return 0;
932 bufferRef.SetParent(GetFile());
933 bufferRef.SetPidOffset(fPidOffset);
934
935 auto storeBuffer = fBuffer;
936 if (fObjlen > fNbytes-fKeylen) {
937 fBuffer = bufferRead;
938 memcpy(bufferRef.Buffer(),fBuffer,fKeylen);
939 } else {
940 fBuffer = bufferRef.Buffer();
941 ReadFile(); //Read object structure from file
942 }
943 fBuffer = storeBuffer;
944
945 // get version of key
946 bufferRef.SetBufferOffset(sizeof(fNbytes));
947 Version_t kvers = bufferRef.ReadVersion();
948
949 bufferRef.SetBufferOffset(fKeylen);
950 TObject *tobj = 0;
951 // Create an instance of this class
952
953 char *pobj = (char*)cl->New();
954 if (!pobj) {
955 Error("ReadObjWithBuffer", "Cannot create new object of class %s", fClassName.Data());
956 return 0;
957 }
958 Int_t baseOffset = cl->GetBaseClassOffset(TObject::Class());
959 if (baseOffset==-1) {
960 // cl does not inherit from TObject.
961 // Since this is not possible yet, the only reason we could reach this code
962 // is because something is screw up in the ROOT code.
963 Fatal("ReadObjWithBuffer","Incorrect detection of the inheritance from TObject for class %s.\n",
964 fClassName.Data());
965 }
966 tobj = (TObject*)(pobj+baseOffset);
967
968 if (kvers > 1)
969 bufferRef.MapObject(pobj,cl); //register obj in map to handle self reference
970
971 if (fObjlen > fNbytes-fKeylen) {
972 Int_t nout = UnzipBuffer(bufferRef.Buffer(), bufferRead);
973 if (nout) {
974 tobj->Streamer(bufferRef); //does not work with example 2 above
975 } else {
976 // Even-though we have a TObject, if the class is emulated the virtual
977 // table may not be 'right', so let's go via the TClass.
978 cl->Destructor(pobj);
979 return nullptr;
980 }
981 } else {
982 tobj->Streamer(bufferRef);
983 }
984
985 if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
986
988 TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
989 dir->SetName(GetName());
990 dir->SetTitle(GetTitle());
991 dir->SetMother(fMotherDir);
992 fMotherDir->Append(dir);
993 }
994
995 // Append the object to the directory if requested:
996 {
998 if (addfunc) {
999 addfunc(pobj, fMotherDir);
1000 }
1001 }
1002
1003 return tobj;
1004}
1005
1006////////////////////////////////////////////////////////////////////////////////
1007/// To read an object (non deriving from TObject) from the file.
1008///
1009/// If expectedClass is not null, we checked that that actual class of the
1010/// object stored is suitable to be stored in a pointer pointing to an object
1011/// of class 'expectedClass'. We also adjust the value of the returned address
1012/// so that it is suitable to be cast (C-Style)
1013/// a pointer pointing to an object of class 'expectedClass'.
1014///
1015/// So for example if the class Bottom inherits from Top and the object
1016/// stored is of type Bottom you can safely do:
1017/// ~~~{.cpp}
1018/// auto TopClass = TClass::GetClass("Top");
1019/// auto ptr = (Top*) key->ReadObjectAny( TopClass );
1020/// if (ptr==0) printError("the object stored in the key is not of the expected type\n");
1021/// ~~~
1022/// The object associated to this key is read from the file into memory.
1023/// Once the key structure is read (via Streamer) the class identifier
1024/// of the object is known.
1025/// Using the class identifier we find the TClass object for this class.
1026/// A TClass object contains a full description (i.e. dictionary) of the
1027/// associated class. In particular the TClass object can create a new
1028/// object of the class type it describes. This new object now calls its
1029/// Streamer function to rebuilt itself.
1030
1031void *TKey::ReadObjectAny(const TClass* expectedClass)
1032{
1034 if (!bufferRef.Buffer()) {
1035 Error("ReadObj", "Cannot allocate buffer: fObjlen = %d", fObjlen);
1036 return 0;
1037 }
1038 if (GetFile()==0) return 0;
1039 bufferRef.SetParent(GetFile());
1040 bufferRef.SetPidOffset(fPidOffset);
1041
1042 std::unique_ptr<char []> compressedBuffer;
1043 auto storeBuffer = fBuffer;
1044 if (fObjlen > fNbytes-fKeylen) {
1045 compressedBuffer.reset(new char[fNbytes]);
1046 fBuffer = compressedBuffer.get();
1047 ReadFile(); //Read object structure from file
1048 memcpy(bufferRef.Buffer(),fBuffer,fKeylen);
1049 } else {
1050 fBuffer = bufferRef.Buffer();
1051 ReadFile(); //Read object structure from file
1052 }
1053 fBuffer = storeBuffer;
1054
1055 // get version of key
1056 bufferRef.SetBufferOffset(sizeof(fNbytes));
1057 Version_t kvers = bufferRef.ReadVersion();
1058
1059 bufferRef.SetBufferOffset(fKeylen);
1060 TClass *cl = TClass::GetClass(fClassName.Data());
1061 TClass *clOnfile = 0;
1062 if (!cl) {
1063 Error("ReadObjectAny", "Unknown class %s", fClassName.Data());
1064 return 0;
1065 }
1066 Int_t baseOffset = 0;
1067 if (expectedClass) {
1068 // baseOffset will be -1 if cl does not inherit from expectedClass
1069 baseOffset = cl->GetBaseClassOffset(expectedClass);
1070 if (baseOffset == -1) {
1071 // The 2 classes are unrelated, maybe there is a converter between the 2.
1072
1073 if (!expectedClass->GetSchemaRules() ||
1074 !expectedClass->GetSchemaRules()->HasRuleWithSourceClass(cl->GetName()))
1075 {
1076 // There is no converter
1077 return 0;
1078 }
1079 baseOffset = 0; // For now we do not support requesting from a class that is the base of one of the class for which there is transformation to ....
1080 clOnfile = cl;
1081 cl = const_cast<TClass*>(expectedClass);
1082 if (gDebug > 0)
1083 Info("ReadObjectAny", "Using Converter StreamerInfo from %s to %s", clOnfile->GetName(),
1084 expectedClass->GetName());
1085 }
1086 if (cl->GetState() > TClass::kEmulated && expectedClass->GetState() <= TClass::kEmulated) {
1087 //we cannot mix a compiled class with an emulated class in the inheritance
1088 Warning("ReadObjectAny",
1089 "Trying to read an emulated class (%s) to store in a compiled pointer (%s)",
1090 cl->GetName(),expectedClass->GetName());
1091 }
1092 }
1093 // Create an instance of this class
1094
1095 void *pobj = cl->New();
1096 if (!pobj) {
1097 Error("ReadObjectAny", "Cannot create new object of class %s", fClassName.Data());
1098 return 0;
1099 }
1100
1101 if (kvers > 1)
1102 bufferRef.MapObject(pobj,cl); //register obj in map to handle self reference
1103
1104 if (fObjlen > fNbytes-fKeylen) {
1105 Int_t nout = UnzipBuffer(bufferRef.Buffer(), compressedBuffer.get());
1106 if (nout) {
1107 cl->Streamer((void*)pobj, bufferRef, clOnfile); //read object
1108 } else {
1109 cl->Destructor(pobj);
1110 return nullptr;
1111 }
1112 } else {
1113 cl->Streamer((void*)pobj, bufferRef, clOnfile); //read object
1114 }
1115
1116 if (cl->IsTObject()) {
1117 auto tobjBaseOffset = cl->GetBaseClassOffset(TObject::Class());
1118 if (tobjBaseOffset == -1) {
1119 Fatal("ReadObj","Incorrect detection of the inheritance from TObject for class %s.\n",
1120 fClassName.Data());
1121 }
1122 TObject *tobj = (TObject*)( ((char*)pobj) + tobjBaseOffset);
1123
1124 // See similar adjustments in ReadObj
1125 if (gROOT->GetForceStyle()) tobj->UseCurrentStyle();
1126
1128 TDirectory *dir = static_cast<TDirectoryFile*>(tobj);
1129 dir->SetName(GetName());
1130 dir->SetTitle(GetTitle());
1131 dir->SetMother(fMotherDir);
1132 fMotherDir->Append(dir);
1133 }
1134 }
1135
1136 {
1137 // Append the object to the directory if requested:
1139 if (addfunc) {
1140 addfunc(pobj, fMotherDir);
1141 }
1142 }
1143
1144 return ( ((char*)pobj) + baseOffset );
1145}
1146
1147////////////////////////////////////////////////////////////////////////////////
1148/// To read an object from the file.
1149///
1150/// The object associated to this key is read from the file into memory.
1151/// Before invoking this function, obj has been created via the
1152/// default constructor.
1153
1155{
1156 if (!obj || (GetFile()==0)) return 0;
1157
1159 bufferRef.SetParent(GetFile());
1160 bufferRef.SetPidOffset(fPidOffset);
1161
1162 if (fVersion > 1)
1163 bufferRef.MapObject(obj); //register obj in map to handle self reference
1164
1165 std::unique_ptr<char []> compressedBuffer;
1166 auto storeBuffer = fBuffer;
1167 if (fObjlen > fNbytes-fKeylen) {
1168 compressedBuffer.reset(new char[fNbytes]);
1169 fBuffer = compressedBuffer.get();
1170 ReadFile(); //Read object structure from file
1171 memcpy(bufferRef.Buffer(),fBuffer,fKeylen);
1172 } else {
1173 fBuffer = bufferRef.Buffer();
1174 ReadFile(); //Read object structure from file
1175 }
1176 fBuffer = storeBuffer;
1177
1178 bufferRef.SetBufferOffset(fKeylen);
1179 if (fObjlen > fNbytes-fKeylen) {
1180 Int_t nout = UnzipBuffer(bufferRef.Buffer(), compressedBuffer.get());
1181 if (nout)
1182 obj->Streamer(bufferRef);
1183 } else {
1184 obj->Streamer(bufferRef);
1185 }
1186
1187 // Append the object to the directory if requested:
1188 {
1189 ROOT::DirAutoAdd_t addfunc = obj->IsA()->GetDirectoryAutoAdd();
1190 if (addfunc) {
1191 addfunc(obj, fMotherDir);
1192 }
1193 }
1194
1195 return fNbytes;
1196}
1197
1198////////////////////////////////////////////////////////////////////////////////
1199/// Decode input buffer.
1200///
1201/// In some situation will add key to gDirectory.
1202
1203void TKey::ReadBuffer(char *&buffer)
1204{
1205 ReadKeyBuffer(buffer);
1206
1207 if (!gROOT->ReadingObject() && gDirectory) {
1208 if (fSeekPdir != gDirectory->GetSeekDir()) gDirectory->AppendKey(this);
1209 }
1210}
1211
1212////////////////////////////////////////////////////////////////////////////////
1213/// Decode input buffer.
1214
1215void TKey::ReadKeyBuffer(char *&buffer)
1216{
1217 frombuf(buffer, &fNbytes);
1218 if (fNbytes < 0) {
1219 Error("ReadKeyBuffer", "The value of fNbytes is negative (%d): cannot continue to read the key buffer.", fNbytes);
1220 MakeZombie();
1221 fNbytes = 0;
1222 return;
1223 }
1224 Version_t version;
1225 frombuf(buffer,&version);
1226 fVersion = (Int_t)version;
1227 frombuf(buffer, &fObjlen);
1228 if (fObjlen < 0) {
1229 Error("ReadKeyBuffer", "The value of fObjlen is negative (%d): cannot continue to read the key buffer.", fObjlen);
1230 MakeZombie();
1231 fObjlen = 0;
1232 return;
1233 }
1234 fDatime.ReadBuffer(buffer);
1235 frombuf(buffer, &fKeylen);
1236 if (fKeylen < 0) {
1237 Error("ReadKeyBuffer", "The value of fKeylen is negative (%d): cannot continue to read the key buffer.", fKeylen);
1238 MakeZombie();
1239 fKeylen = 0;
1240 return;
1241 }
1242
1243 if (fNbytes < fKeylen) {
1244 Error("ReadKeyBuffer", "fNbytes (%d) < fKeylen (%d): cannot continue to read the key buffer.", fNbytes, fKeylen);
1245 MakeZombie();
1246 return;
1247 }
1248
1249 constexpr auto maxInt_t = std::numeric_limits<Int_t>::max();
1250 if (fKeylen > (maxInt_t - fObjlen)) {
1251 Error("ReadKeyBuffer", "fObjlen (%d) + fKeylen (%d) > max int (%d): cannot continue to read the key buffer.", fObjlen, fKeylen, maxInt_t);
1252 MakeZombie();
1253 return;
1254 }
1255
1256 frombuf(buffer, &fCycle);
1257 if (fVersion > 1000) {
1258 frombuf(buffer, &fSeekKey);
1259
1260 // We currently store in the 16 highest bit of fSeekPdir the value of
1261 // fPidOffset. This offset is used when a key (or basket) is transferred from one
1262 // file to the other. In this case the TRef and TObject might have stored a
1263 // pid index (to retrieve TProcessIDs) which refered to their order on the original
1264 // file, the fPidOffset is to be added to those values to correctly find the
1265 // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1266 // and need to be zero for new key/basket.
1267 Long64_t pdir;
1268 frombuf(buffer, &pdir);
1269 fPidOffset = pdir >> kPidOffsetShift;
1270 fSeekPdir = pdir & kPidOffsetMask;
1271 } else {
1272 UInt_t seekkey,seekdir;
1273 frombuf(buffer, &seekkey); fSeekKey = (Long64_t)seekkey;
1274 frombuf(buffer, &seekdir); fSeekPdir= (Long64_t)seekdir;
1275 }
1276 fClassName.ReadBuffer(buffer);
1277 //the following test required for forward and backward compatibility
1278 if (fClassName == "TDirectory") {
1279 fClassName = "TDirectoryFile";
1281 }
1282
1283 fName.ReadBuffer(buffer);
1284 fTitle.ReadBuffer(buffer);
1285}
1286
1287////////////////////////////////////////////////////////////////////////////////
1288/// Read the key structure from the file
1289
1291{
1292 TFile* f = GetFile();
1293 if (f==0) return kFALSE;
1294
1295 Int_t nsize = fNbytes;
1296 f->Seek(fSeekKey);
1297 if( f->ReadBuffer(fBuffer,nsize) )
1298 {
1299 Error("ReadFile", "Failed to read data.");
1300 return kFALSE;
1301 }
1302 if (gDebug) {
1303 std::cout << "TKey Reading "<<nsize<< " bytes at address "<<fSeekKey<<std::endl;
1304 }
1305 return kTRUE;
1306}
1307
1308////////////////////////////////////////////////////////////////////////////////
1309/// Set parent in key buffer.
1310
1311void TKey::SetParent(const TObject *parent)
1312{
1313 if (fBufferRef) fBufferRef->SetParent((TObject*)parent);
1314}
1315
1316////////////////////////////////////////////////////////////////////////////////
1317/// Reset the key as it had not been 'filled' yet.
1318
1320{
1321 fPidOffset = 0;
1322 fNbytes = 0;
1323 fBuffer = 0;
1324 fObjlen = 0;
1325 fCycle = 0;
1326 fSeekPdir = 0;
1327 fSeekKey = 0;
1328 fLeft = 0;
1329 fDatime = (UInt_t)0;
1330
1331 // fBufferRef and fKeylen intentionally not reset/changed
1332
1334}
1335
1336////////////////////////////////////////////////////////////////////////////////
1337/// Return the size in bytes of the key header structure.
1338///
1339/// An explanation about the nbytes (Int_t nbytes) variable used in the
1340/// function. The size of fSeekKey and fSeekPdir is 8 instead of 4 if version is
1341/// greater than 1000.
1342/// | Component | Sizeof |
1343/// |-------------------|------------|
1344/// | fNbytes | 4 |
1345/// | sizeof(Version_t) | 2 |
1346/// | fObjlen | 4 |
1347/// | fDatime | 4 |
1348/// | fKeylen | 2 |
1349/// | fCycle | 2 |
1350/// | fSeekKey | 4 or 8 |
1351/// | fSeekPdir | 4 or 8 |
1352/// | **FIXED TOTAL** | 26 or 34 |
1353/// | fClassName | 1+ bytes |
1354/// | fName | 1+ bytes |
1355/// | fTitle | 1+ bytes |
1356/// | **TOTAL** | 29+ or 37+ |
1357
1359{
1360 Int_t nbytes = 22; if (fVersion > 1000) nbytes += 8;
1361 nbytes += fDatime.Sizeof();
1363 nbytes += 11; // strlen("TDirectory")+1
1364 } else {
1365 nbytes += fClassName.Sizeof();
1366 }
1367 nbytes += fName.Sizeof();
1368 nbytes += fTitle.Sizeof();
1369 return nbytes;
1370}
1371
1372////////////////////////////////////////////////////////////////////////////////
1373/// Stream a class object.
1374
1376{
1377 Version_t version;
1378 if (b.IsReading()) {
1379 b >> fNbytes;
1380 b >> version; fVersion = (Int_t)version;
1381 b >> fObjlen;
1382 fDatime.Streamer(b);
1383 b >> fKeylen;
1384 b >> fCycle;
1385 if (fVersion > 1000) {
1386 b >> fSeekKey;
1387
1388 // We currently store in the 16 highest bit of fSeekPdir the value of
1389 // fPidOffset. This offset is used when a key (or basket) is transferred from one
1390 // file to the other. In this case the TRef and TObject might have stored a
1391 // pid index (to retrieve TProcessIDs) which refered to their order on the original
1392 // file, the fPidOffset is to be added to those values to correctly find the
1393 // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1394 // and need to be zero for new key/basket.
1395 Long64_t pdir;
1396 b >> pdir;
1397 fPidOffset = pdir >> kPidOffsetShift;
1398 fSeekPdir = pdir & kPidOffsetMask;
1399 } else {
1400 UInt_t seekkey, seekdir;
1401 b >> seekkey; fSeekKey = (Long64_t)seekkey;
1402 b >> seekdir; fSeekPdir= (Long64_t)seekdir;
1403 }
1404 fClassName.Streamer(b);
1405 //the following test required for forward and backward compatibility
1406 if (fClassName == "TDirectory") {
1407 fClassName = "TDirectoryFile";
1409 }
1410 fName.Streamer(b);
1411 fTitle.Streamer(b);
1412 if (fKeylen < 0) {
1413 Error("Streamer","The value of fKeylen is incorrect (%d) ; trying to recover by setting it to zero",fKeylen);
1414 MakeZombie();
1415 fKeylen = 0;
1416 }
1417 if (fObjlen < 0) {
1418 Error("Streamer","The value of fObjlen is incorrect (%d) ; trying to recover by setting it to zero",fObjlen);
1419 MakeZombie();
1420 fObjlen = 0;
1421 }
1422 if (fNbytes < 0) {
1423 Error("Streamer","The value of fNbytes is incorrect (%d) ; trying to recover by setting it to zero",fNbytes);
1424 MakeZombie();
1425 fNbytes = 0;
1426 }
1427
1428 } else {
1429 b << fNbytes;
1430 version = (Version_t)fVersion;
1431 b << version;
1432 b << fObjlen;
1433 if (fDatime.Get() == 0) fDatime.Set();
1435 TDatime((UInt_t) 1).Streamer(b);
1436 else
1437 fDatime.Streamer(b);
1438 b << fKeylen;
1439 b << fCycle;
1440 if (fVersion > 1000) {
1441 b << fSeekKey;
1442
1443 // We currently store in the 16 highest bit of fSeekPdir the value of
1444 // fPidOffset. This offset is used when a key (or basket) is transferred from one
1445 // file to the other. In this case the TRef and TObject might have stored a
1446 // pid index (to retrieve TProcessIDs) which refered to their order on the original
1447 // file, the fPidOffset is to be added to those values to correctly find the
1448 // TProcessID. This fPidOffset needs to be increment if the key/basket is copied
1449 // and need to be zero for new key/basket.
1451 b << pdir;
1452 } else {
1453 b << (Int_t)fSeekKey;
1454 b << (Int_t)fSeekPdir;
1455 }
1457 // We want to record "TDirectory" instead of TDirectoryFile so that the file can be read by ancient version of ROOT.
1458 b.WriteTString(gTDirectoryString);
1459 } else {
1460 fClassName.Streamer(b);
1461 }
1462 fName.Streamer(b);
1463 fTitle.Streamer(b);
1464 }
1465}
1466
1467////////////////////////////////////////////////////////////////////////////////
1468/// Write the encoded object supported by this key.
1469/// The function returns the number of bytes committed to the file.
1470/// If a write error occurs, the number of bytes returned is -1.
1471
1473{
1474 if (!f) f = GetFile();
1475 if (!f) return -1;
1476
1477 Int_t nsize = fNbytes;
1478 char *buffer = fBuffer;
1479 if (cycle) {
1480 fCycle = cycle;
1481 FillBuffer(buffer);
1482 buffer = fBuffer;
1483 }
1484
1485 if (fLeft > 0) nsize += sizeof(Int_t);
1486 f->Seek(fSeekKey);
1487 Bool_t result = f->WriteBuffer(buffer,nsize);
1488 //f->Flush(); Flushing takes too much time.
1489 // Let user flush the file when they want.
1490 if (gDebug) {
1491 std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1492 <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1493 }
1494
1495 DeleteBuffer();
1496 return result==kTRUE ? -1 : nsize;
1497}
1498
1499////////////////////////////////////////////////////////////////////////////////
1500/// Write the encoded object supported by this key.
1501/// The function returns the number of bytes committed to the file.
1502/// If a write error occurs, the number of bytes returned is -1.
1503
1505{
1506 if (!f) f = GetFile();
1507 if (!f) return -1;
1508
1509 Int_t nsize = fNbytes;
1510 char *buffer = fBuffer;
1511
1512 if (fLeft > 0) nsize += sizeof(Int_t);
1513 f->Seek(fSeekKey);
1514 Bool_t result = f->WriteBuffer(buffer,nsize);
1515 //f->Flush(); Flushing takes too much time.
1516 // Let user flush the file when they want.
1517 if (gDebug) {
1518 std::cout <<" TKey Writing "<<nsize<< " bytes at address "<<fSeekKey
1519 <<" for ID= " <<GetName()<<" Title= "<<GetTitle()<<std::endl;
1520 }
1521
1522 return result==kTRUE ? -1 : nsize;
1523}
1524
1525////////////////////////////////////////////////////////////////////////////////
1526/// Title can keep 32x32 xpm thumbnail/icon of the parent object.
1527
1528const char *TKey::GetIconName() const
1529{
1530 return (!fTitle.IsNull() && fTitle.BeginsWith("/* ") ? fTitle.Data() : 0);
1531}
1532
1533////////////////////////////////////////////////////////////////////////////////
1534/// Returns title (title can contain 32x32 xpm thumbnail/icon).
1535
1536const char *TKey::GetTitle() const
1537{
1538 if (!fTitle.IsNull() && fTitle.BeginsWith("/* ")) { // title contains xpm thumbnail
1539 static TString ret;
1540 int start = fTitle.Index("/*") + 3;
1541 int stop = fTitle.Index("*/") - 1;
1542 ret = fTitle(start, stop - start);
1543 return ret.Data();
1544 }
1545 return fTitle.Data();
1546}
void frombuf(char *&buf, Bool_t *x)
Definition Bytes.h:270
void tobuf(char *&buf, Bool_t x)
Definition Bytes.h:55
#define b(i)
Definition RSha256.hxx:100
#define f(i)
Definition RSha256.hxx:104
char * ret
Definition Rotated.cxx:221
start
Definition Rotated.cxx:223
unsigned short UShort_t
Unsigned Short integer 2 bytes (unsigned short).
Definition RtypesCore.h:54
int Int_t
Signed integer 4 bytes (int).
Definition RtypesCore.h:59
short Version_t
Class version identifier (short).
Definition RtypesCore.h:79
unsigned char UChar_t
Unsigned Character 1 byte (unsigned char).
Definition RtypesCore.h:52
unsigned int UInt_t
Unsigned integer 4 bytes (unsigned int).
Definition RtypesCore.h:60
bool Bool_t
Boolean (0=false, 1=true) (bool).
Definition RtypesCore.h:77
short Short_t
Signed Short integer 2 bytes (short).
Definition RtypesCore.h:53
constexpr Bool_t kFALSE
Definition RtypesCore.h:108
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:83
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:84
constexpr Bool_t kTRUE
Definition RtypesCore.h:107
const char Option_t
Option string (const char).
Definition RtypesCore.h:80
#define gDirectory
Definition TDirectory.h:385
#define R__ASSERT(e)
Checks condition e and reports a fatal error if it's false.
Definition TError.h:125
#define gFile
Definition TFile.h:439
char name[80]
Definition TGX11.cxx:148
const ULong64_t kPidOffsetMask
Definition TKey.cxx:74
static const TString gTDirectoryString("TDirectory")
const Int_t kTitleMax
Definition TKey.cxx:71
std::atomic< UInt_t > keyAbsNumber
Definition TKey.cxx:81
const UChar_t kPidOffsetShift
Definition TKey.cxx:78
Int_t gDebug
Definition TROOT.cxx:777
#define gROOT
Definition TROOT.h:417
Bool_t HasRuleWithSourceClass(const TString &source) const
Return True if we have any rule whose source class is 'source'.
Using a TBrowser one can browse all ROOT objects.
Definition TBrowser.h:37
The concrete implementation of TBuffer for writing/reading to/from a ROOT file or socket.
Definition TBufferFile.h:47
Version_t ReadVersion(UInt_t *start=nullptr, UInt_t *bcnt=nullptr, const TClass *cl=nullptr) override
Read class version from I/O buffer.
void MapObject(const TObject *obj, UInt_t offset=1) override
Add object to the fMap container.
void SetPidOffset(UShort_t offset) override
This offset is used when a key (or basket) is transferred from one file to the other.
Buffer base class used for serializing objects.
Definition TBuffer.h:43
void SetParent(TObject *parent)
Set parent owning this buffer.
Definition TBuffer.cxx:269
@ kWrite
Definition TBuffer.h:73
@ kRead
Definition TBuffer.h:73
void SetBufferOffset(Int_t offset=0)
Definition TBuffer.h:93
char * Buffer() const
Definition TBuffer.h:96
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=nullptr) const
Definition TClass.h:626
void Browse(TBrowser *b) override
This method is called by a browser to get the class information.
Definition TClass.cxx:2017
EState GetState() const
Definition TClass.h:504
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition TClass.cxx:5048
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition TClass.cxx:5470
void * DynamicCast(const TClass *base, void *obj, Bool_t up=kTRUE)
Cast obj of this class type up to baseclass cl if up is true.
Definition TClass.cxx:4973
ROOT::DirAutoAdd_t GetDirectoryAutoAdd() const
Return the wrapper around the directory auto add function.
Definition TClass.cxx:7652
@ kDummyNew
Definition TClass.h:110
const ROOT::Detail::TSchemaRuleSet * GetSchemaRules() const
Return the set of the schema rules if any.
Definition TClass.cxx:1934
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition TClass.cxx:6043
Bool_t InheritsFrom(const char *cl) const override
Return kTRUE if this class inherits from a class with name "classname".
Definition TClass.cxx:4932
Int_t GetBaseClassOffset(const TClass *toBase, void *address=nullptr, bool isDerivedObject=true)
Definition TClass.cxx:2812
Bool_t HasDefaultConstructor(Bool_t testio=kFALSE) const
Return true if we have access to a constructor usable for I/O.
Definition TClass.cxx:7550
@ kEmulated
Definition TClass.h:128
TClass * GetActualClass(const void *object) const
Return a pointer to the real class of the object.
Definition TClass.cxx:2614
static TClass * GetClass(const char *name, Bool_t load=kTRUE, Bool_t silent=kFALSE)
Static method returning pointer to TClass of the specified class name.
Definition TClass.cxx:2994
static TClass * Class()
This class stores the date and time with a precision of one second in an unsigned 32 bit word (950130...
Definition TDatime.h:37
void FillBuffer(char *&buffer)
Encode Date/Time into buffer, used by I/O system.
Definition TDatime.cxx:228
virtual void Streamer(TBuffer &)
Stream a object of type TDatime.
Definition TDatime.cxx:415
Long64_t GetSeekDir() const override
static TClass * Class()
Describe directory structure in memory.
Definition TDirectory.h:45
void SetName(const char *newname) override
Set the name for directory If the directory name is changed after the directory was written once,...
virtual void SetMother(TObject *mother)
Definition TDirectory.h:259
A file, usually with extension .root, that stores data and code in the form of serialized objects in ...
Definition TFile.h:130
@ kStartBigFile
Definition TFile.h:278
Int_t GetCompressionLevel() const
Definition TFile.h:483
virtual Long64_t GetEND() const
Definition TFile.h:319
virtual void MakeFree(Long64_t first, Long64_t last)
Mark unused bytes on the file.
Definition TFile.cxx:1496
Int_t GetCompressionAlgorithm() const
Definition TFile.h:477
@ kReproducible
Definition TFile.h:271
Service class for TFile.
Definition TFree.h:27
Long64_t GetLast() const
Definition TFree.h:41
void SetFirst(Long64_t first)
Definition TFree.h:44
void SetLast(Long64_t last)
Definition TFree.h:45
Long64_t GetFirst() const
Definition TFree.h:40
const char * GetTitle() const override
Returns title (title can contain 32x32 xpm thumbnail/icon).
Definition TKey.cxx:1536
static constexpr Version_t Class_Version()
Definition TKey.h:118
void Delete(Option_t *option="") override
Delete an object from the file.
Definition TKey.cxx:572
@ kReproducible
Definition TKey.h:33
@ kIsDirectoryFile
Definition TKey.h:32
Int_t Sizeof() const override
Return the size in bytes of the key header structure.
Definition TKey.cxx:1358
TKey()
TKey default constructor.
Definition TKey.cxx:87
~TKey() override
TKey default destructor.
Definition TKey.cxx:559
TFile * GetFile() const
Returns file to which key belong.
Definition TKey.cxx:619
virtual void Keep()
Set the "KEEP" status.
Definition TKey.cxx:719
const char * GetIconName() const override
Title can keep 32x32 xpm thumbnail/icon of the parent object.
Definition TKey.cxx:1528
Int_t Read(const char *name) override
Read contents of object with specified name from the current directory.
Definition TKey.h:56
Int_t UnzipBuffer(char *targetBuffer, const char *compressedBuffer) const
Core of uncompressing the key payload.
Definition TKey.cxx:391
TDatime fDatime
Date/Time of insertion in file.
Definition TKey.h:44
TBuffer * fBufferRef
Pointer to the TBuffer object.
Definition TKey.h:52
UShort_t fPidOffset
!Offset to be added to the pid index in this key/buffer. This is actually saved in the high bits of f...
Definition TKey.h:53
virtual void IncrementPidOffset(UShort_t offset)
Increment fPidOffset by 'offset'.
Definition TKey.cxx:684
Short_t GetKeep() const
Returns the "KEEP" status.
Definition TKey.cxx:627
Int_t fVersion
Key version identifier.
Definition TKey.h:41
Bool_t IsFolder() const override
Check if object referenced by the key is a folder.
Definition TKey.cxx:698
Int_t fLeft
Number of bytes left in current segment.
Definition TKey.h:50
virtual const char * GetClassName() const
Definition TKey.h:77
Short_t fKeylen
Number of bytes for the key itself.
Definition TKey.h:45
virtual Bool_t ReadFile()
Read the key structure from the file.
Definition TKey.cxx:1290
TKey(const TKey &)=delete
void Browse(TBrowser *b) override
Read object from disk and call its Browse() method.
Definition TKey.cxx:461
virtual Int_t WriteFileKeepBuffer(TFile *f=nullptr)
Write the encoded object supported by this key.
Definition TKey.cxx:1504
Long64_t fSeekKey
Location of object on file.
Definition TKey.h:47
void Build(TDirectory *motherDir, const char *classname, Long64_t filepos)
Method used in all TKey constructor to initialize basic data fields.
Definition TKey.cxx:423
char * fBuffer
Object buffer.
Definition TKey.h:51
Long64_t fSeekPdir
Location of parent directory on file.
Definition TKey.h:48
virtual void SetParent(const TObject *parent)
Set parent in key buffer.
Definition TKey.cxx:1311
virtual void * ReadObjectAny(const TClass *expectedClass)
To read an object (non deriving from TObject) from the file.
Definition TKey.cxx:1031
void ReadKeyBuffer(char *&buffer)
Decode input buffer.
Definition TKey.cxx:1215
Int_t fNbytes
Number of bytes for the whole key on file (key header and data).
Definition TKey.h:42
Int_t fObjlen
Length of uncompressed object in bytes.
Definition TKey.h:43
void Reset()
Reset the key as it had not been 'filled' yet.
Definition TKey.cxx:1319
Short_t fCycle
Cycle number.
Definition TKey.h:46
virtual TObject * ReadObjWithBuffer(char *bufferRead)
To read a TObject* from bufferRead.
Definition TKey.cxx:913
virtual void ls(Bool_t current) const
List Key contents.
Definition TKey.cxx:728
Short_t GetCycle() const
Return cycle number associated to this key.
Definition TKey.cxx:611
virtual TObject * ReadObj()
To read a TObject* from the file.
Definition TKey.cxx:792
virtual void Create(Int_t nbytes, TFile *f=nullptr)
Create a TKey object of specified size.
Definition TKey.cxx:493
virtual void DeleteBuffer()
Delete key buffer(s).
Definition TKey.cxx:593
virtual Int_t WriteFile(Int_t cycle=1, TFile *f=nullptr)
Write the encoded object supported by this key.
Definition TKey.cxx:1472
virtual void ReadBuffer(char *&buffer)
Decode input buffer.
Definition TKey.cxx:1203
TDirectory * fMotherDir
!pointer to mother directory
Definition TKey.h:54
TString fClassName
Object Class name.
Definition TKey.h:49
void Print(Option_t *option="") const override
Print key contents.
Definition TKey.cxx:748
void FillBuffer(char *&buffer) override
Encode key header into output buffer.
Definition TKey.cxx:635
void Streamer(TBuffer &) override
Stream a class object.
Definition TKey.cxx:1375
A doubly linked list.
Definition TList.h:38
TObject * Remove(TObject *obj) override
Remove object from the list.
Definition TList.cxx:952
TObject * First() const override
Return the first object in the list. Returns 0 when list is empty.
Definition TList.cxx:789
virtual void SetTitle(const char *title="")
Set the title of the TNamed.
Definition TNamed.cxx:173
const char * GetName() const override
Returns name of object.
Definition TNamed.h:49
TString fTitle
Definition TNamed.h:33
TNamed()
Definition TNamed.h:38
TString fName
Definition TNamed.h:32
virtual Bool_t IsFolder() const
Returns kTRUE in case object contains browsable objects (like containers or lists of other objects).
Definition TObject.cxx:579
Bool_t TestBit(UInt_t f) const
Definition TObject.h:204
virtual void Streamer(TBuffer &)
Stream an object of class TObject.
Definition TObject.cxx:997
virtual const char * ClassName() const
Returns name of class to which the object belongs.
Definition TObject.cxx:227
virtual void UseCurrentStyle()
Set current style settings in this object This function is called when either TCanvas::UseCurrentStyl...
Definition TObject.cxx:909
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1084
static TClass * Class()
virtual void Delete(Option_t *option="")
Delete this object.
Definition TObject.cxx:268
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition TObject.cxx:888
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition TObject.cxx:549
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1098
virtual void Fatal(const char *method, const char *msgfmt,...) const
Issue fatal error message.
Definition TObject.cxx:1126
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition TObject.cxx:899
virtual TClass * IsA() const
Definition TObject.h:248
void MakeZombie()
Definition TObject.h:55
TObject()
TObject constructor.
Definition TObject.h:259
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition TObject.cxx:1072
static void IndentLevel()
Functions used by ls() to indent an object hierarchy.
Definition TROOT.cxx:3052
Basic string class.
Definition TString.h:138
TF1 * f1
Definition legend1.C:11
void(* DirAutoAdd_t)(void *, TDirectory *)
Definition Rtypes.h:120
EValues
Note: this is only temporarily a struct and will become a enum class hence the name convention used.
Definition Compression.h:88