Problem updating TFile

Dear Rooters

When opening TFile in Update mode in my program using the following code fragment:

   TFile *file = 0;
   const char *fname;
   if ((fname = gSystem->ExpandPathName(name))) {
      file = gROOT->GetFile(fname);

      // need to set correct option (why?)
      if (file) {
         if (strcmp(file->GetOption(), "UPDATE") == 0) {
            file->ReOpen(file->GetOption());
         } else {
            file->ReOpen(opt.Data());
         }//if
      }//if
//wrong?      file->SetOption(opt.Data());
//wrong?      file->SetWritable(kTRUE);

      if (!file) { //do not use "else"
         file = TFile::Open(name, opt.Data());
      }//if

      delete [] (char*)fname;
   }//if

I get the following random errors:
(each run causes randomly one of these errors)

Error in TKey::ReadObj: Unknown class 0{æX›Â–8◊Ih¶u\€BbÔ≈æÏ÷CGj"u=3¬¿Ô>cÍp∫A(§
Info in TFile::GetStreamerInfoList: cannot find the StreamerInfo record in file /Volumes/CoreData/CRAN/Workspaces/TestAB/data/Test3RMAall.root

SysError in TFile::Seek: cannot seek to position -1920365292 in file /Volumes/CoreData/CRAN/Workspaces/TestAB/data/Test3RMAall.root, retpos=-1 (Invalid argument)

Error in TFile::Init: file /Volumes/CoreData/CRAN/Workspaces/TestAB/data/Test3RMAall.root is truncated at 837258 bytes: should be 337914381838843904, trying to recover
Info in TFile::Recover: /Volumes/CoreData/CRAN/Workspaces/TestAB/data/Test3RMAall.root, recovered key TDirectory:BackgroundSet at address 410
Warning in TFile::Init: successfully recovered 1 keys
Error in TFile::Init: file /Volumes/CoreData/CRAN/Workspaces/TestAB/data/Test3RMAall.root is truncated at 837258 bytes: should be 337914381838843904, trying to recover
Info in TFile::Recover: /Volumes/CoreData/CRAN/Workspaces/TestAB/data/Test3RMAall.root, recovered key TDirectory:BackgroundSet at address 410
Warning in TFile::Init: successfully recovered 1 keys

Can someone tell me what these errors mean, and give me a hint what might be the reason for these errors?

Thank you in advance.
Best regards
Christian

This sounds like the file is truncated. One possible reason is that you have 2 different process that are trying to update it as the same time.

Cheers,
Philippe.

Dear Philippe

Thank you, this confirms what I have already suspected.

When running my program under root/cint, I can update my file as often as
I want w/o any problems. However, currently I am creating an R-package as
wrapper to my libraries, and R (cran.r-project.org) seems to have
a strange memory management, e.g. it keeps all objects in memory until
I quit R, including the root file created from within R. This has the
effect, that when I update the root file, it only updates the root file
kept in memory but not the saved version. When I open the root browser
(also within the current R session) and inspect the file, it is not
updated. Only quitting the current R-session saves the updated root
file to disk.
When I try to update the root file multiple times from within R, it seems
that R either creates multiple copies of the file or does not know which
copy to update.

Do you have any hint how I could avoid this behavior?
Maybe there is a way to force writing the root file to disk?

Best regards
Christian

Hi,

You could also explicitly ‘Close’ the file. You could try ‘Flush’.
Also it seems that one of the problem is that your R plugin is opening the same file multiple time … maybe this can be prevented within your code?

Cheers,
Philippe

As you see from the following code I am closing the file in every R-callable function, and I use file->Flush():

void XManager::Close(Option_t *option)
{
   if (fFile) {
      if (fFile->IsWritable() && this->Save() == kFALSE) {
         cerr << "Could not save content to file <" << fFile->GetName() << ">."
              << endl;
      }

      if (fIsFileOwner) {SafeDelete(fFile);}
      else              {fFile = 0;} 
   }
}//Close

Bool_t XManager::Save()
{
   Bool_t isSaved = kFALSE;

   if (fFile) {
      if (!fFile->IsWritable()) return kFALSE;

      fFile->Flush();

      isSaved = kTRUE;
   }
   return isSaved;
}//Save

Sorrowly, this seems not to help.

Best regards
Christian

Hi,

Given the name of your function (Save) instead of (or in addition to) Flush (which will ‘flush’ already ‘processed’ byte to the disk, might want to use ‘Write’ (which go through the object attached to the file (histogram, tree) and write their meta data to the file.

Cheers,
Philippe

Dear Philippe

Thank you for this suggestion.
I have tried this already, but sadly this does not work either.

Luckily, I have now found a solution:
In my first code fragment I need to remove the code checking for a file in memory,
i.e.: file = gROOT->GetFile(fname);
I have simply to call: file = TFile::Open(name, opt.Data());

Best regards
Christian