Пример #1
0
int bbcp_File::Read_All(bbcp_BuffPool &inPool, int Vn)
{
    bbcp_FileChkSum *csP = 0;
    bbcp_BuffPool *outPool;
    bbcp_Buffer   *bP;
    pthread_t tid;
    int ec, rc = 0;

// Get the size of the file
//
   if ((bytesLeft = FSp->getSize(IOB->FD())) < 0)
      {bbcp_Emsg("Read", static_cast<int>(-bytesLeft), "stat", iofn);
       inPool.Abort(); return 200;
      }

// Adjust bytes left based on where we will be reading from
//
   bytesLeft -= nextoffset;
   if (bytesLeft < 0)
      {bbcp_Emsg("Read", ESPIPE, "stat", iofn);
       inPool.Abort(); return 200;
      }

// If this is a real-time copy operation, start the rtcopy object
//
   if (rtCopy && !bbcp_RTCopy.Start(FSp, iofn, IOB->FD()))
      {inPool.Abort(); return 200;
      }

// Set up checksumming. We would prefer to do this in the calling thread but
// this is easier. One day we will generalize buffer piping.
//
   if (bbcp_Config.csOpts & bbcp_csVerIn)
      {csP = new bbcp_FileChkSum(&inPool, this, bbcp_Config.csType,
                                 bbcp_Config.csOpts & bbcp_csVerIO);
       if ((rc = bbcp_Thread_Start(bbcp_FileCSX, (void *)csP, &tid)) < 0)
           {bbcp_Emsg("File", rc, "starting file checksum thread.");
            delete csP;
            if (rtCopy) bbcp_RTCopy.Stop();
            inPool.Abort(); return 201;
           }
       outPool =  &csP->csPool;
      } else outPool = &inPool;

// Establish logging options
//
   if (bbcp_Config.Options & bbcp_LOGRD) IOB->Log("DISK", 0);

// Determine what kind of reading we will do here and do it
//
// cerr <<"BLOCKSIZE " <<blockSize <<endl;
        if (bbcp_Config.Options & bbcp_XPIPE)
                        rc = Read_Pipe  (&inPool, outPool);
   else if (blockSize ) rc = Read_Direct(&inPool, outPool);
   else rc = (Vn > 1       ? Read_Vector(&inPool, outPool, Vn)
                           : Read_Normal(&inPool, outPool));

// Delete the real-time copy object if we have one to kill possible thread
//
   if (rtCopy) bbcp_RTCopy.Stop();

// Check if we ended because with an error
//
   if (rc && rc != -ENOBUFS)
      {const char *Act=(bbcp_Config.Options & bbcp_XPIPE ? "piping":"writing");
       bbcp_Emsg("Read", -rc, Act, iofn);
      }

// Now close the input file, make sure no errors occur here
//
   if ((ec = IOB->Close()))
      if (!rc) {bbcp_Emsg("Read", -ec, "closing", iofn); rc = ec;}

// Prepare an empty buffer to shutdown the buffer pipeline. The offet indicates
// how much data should have been sent and received. A negative offset implies
// that we encountered an error.
//
   if (!(bP = inPool.getEmptyBuff())) return 255;
   bP->blen = 0;
   bP->boff = (rc ? -1 : nextoffset);

// Verify check sum if so wanted. Note that is link-level check summing is in
//
   if (csP)
      {csP->csPool.putFullBuff(bP);
       bbcp_Thread_Wait(tid);
       if (!rc && *bbcp_Config.csString)
          {char *csTxt, *csVal = csP->csObj->Final(&csTxt);
           if (memcmp(csVal, bbcp_Config.csValue, csP->csObj->csSize()))
              {bbcp_Fmsg("Read", iofn, "source checksum", bbcp_Config.csString,
                         "does not match", csTxt);
               rc = EILSEQ;
              } else {DEBUG(csP->csObj->Type() <<": " <<csTxt <<' ' <<iofn);}
          }
       delete csP;
      } else inPool.putFullBuff(bP);

// All done
//
   DEBUG("EOF offset=" <<nextoffset <<" rc=" <<rc <<" fn=" <<iofn);
   return rc;
}
Пример #2
0
int bbcp_File::Write_All(bbcp_BuffPool& inPool, int nstrms)
{
    bbcp_FileChkSum* csP = 0;
    bbcp_BuffPool* iBP;
    pthread_t tid;
    int ec, rc, csType;

// If we have no IOB, then do a simple in-line passthru
//
    if (!IOB)
        return Passthru(&inPool, &bbcp_CPool, 0, nstrms);

// Establish checksum options as well as ordering options. Note that we do
// not support checksums in unordered streams and should have been prohibited.
//
    csType = bbcp_Config.csOpts & bbcp_csVerOut ? bbcp_Config.csType : bbcp_csNOP;
    if (bbcp_Config.csOpts & bbcp_csVerOut || bbcp_Config.Options & bbcp_ORDER)
    {
        csP = new bbcp_FileChkSum(&inPool, this, csType,
                                  bbcp_Config.csOpts & bbcp_csVerIO, nstrms);
        nstrms = 1;
        if ((rc = bbcp_Thread_Start(bbcp_FileCSY, (void*)csP, &tid)) < 0)
        {
            bbcp_Emsg("File", rc, "starting file checksum thread.");
            if (csP)
                delete csP;
            if (IOB)
                IOB->Close();
            return 201;
        }
        else
            iBP = &(csP->csPool);
    }
    else
        iBP = &inPool;

// Establish logging options
//
    if (bbcp_Config.Options & bbcp_LOGRD)
        IOB->Log(0, "DISK");

// Determine what kind of writing we will do here and do it
//
    rc = (blockSize ? Write_Direct(iBP, &inPool, nstrms)
                    : Write_Normal(iBP, &inPool, nstrms));

// Check if we ended because of an error or end of file
//
    if (rc < 0 && rc != -ENOBUFS)
    {
        const char* Act = (bbcp_Config.Options & bbcp_XPIPE ? "piping" : "writing");
        bbcp_Emsg("Write", -rc, Act, iofn);
        inPool.Abort();
    }

// Check if we should verify a checksum
//
    if (csP)
    {
        bbcp_Thread_Wait(tid);
        if (!rc && csP->csObj)
            rc = verChkSum(csP);
        delete csP;
    }

// If checksums are being printed, send off ours if we have it
//
    if (bbcp_Config.csOpts & bbcp_csPrint && *bbcp_Config.csString)
        cout << "200 cks: " << bbcp_Config.csString << ' ' << iofn << endl;

// Check if we should fsync this file
//
    if (!rc && IOB && (bbcp_Config.Options & bbcp_FSYNC)
        && (rc = FSp->Fsync((bbcp_Config.Options & bbcp_DSYNC ? iofn : 0), IOB->FD())))
        bbcp_Emsg("Write", -rc, "synchronizing", iofn);

// Close the output file and make sure it's ok
//
    if (IOB && (ec = IOB->Close())) if (!rc)
    {
        bbcp_Emsg("Write", -ec, "closing", iofn);
        rc = ec;
    }

// All done
//
    return rc;
}
Пример #3
0
int bbcp_Node::RecvFile(bbcp_FileSpec *fp, bbcp_Node *Remote)
{
   static const int wOnly = S_IWUSR;

   const char *Args = 0, *Act = "opening", *Path = fp->targpath;
   long tretc = 0;
   int i, oflag, retc, Mode = wOnly, progtid = 0;
   long long startoff = 0;
   pid_t Child[2] = {0,0};
   bbcp_File *outFile, *seqFile = 0;
   bbcp_ZCX *cxp = 0;
   pthread_t tid, link_tid[BBCP_MAXSTREAMS+4];
   bbcp_Timer Elapsed_Timer;
   bbcp_ProgMon *pmp = 0;
   float CRatio;

// Perform Force or Append processing
//
        if (bbcp_Config.Options & bbcp_XPIPE)
           {oflag = O_WRONLY;
            Path = bbcp_Config.snkSpec->pathname;
            Args = bbcp_Config.snkSpec->fileargs;
            if (bbcp_Config.snkSpec->Info.Otype != 'p') Act = "running";
               else {Mode |= S_IFIFO;
                     if (Args)
                        {bbcp_Fmsg("RecvFile",
                                   "Spaces disallowed in named output pipe",Path);
                         return -EINVAL;
                        }
                    }
           }
   else if (bbcp_Config.Options & bbcp_FORCE)
           {if (!(bbcp_Config.Options & bbcp_NOUNLINK))
               fp->FSys()->RM(Path);
            oflag = O_WRONLY | O_CREAT | O_TRUNC;
           }
   else if (bbcp_Config.Options & bbcp_APPEND)
           {if (retc = fp->WriteSigFile()) return retc;
            if (startoff = fp->targetsz) oflag = O_WRONLY;
               else oflag = O_CREAT | O_WRONLY;
           }
   else    oflag = O_WRONLY | O_CREAT | O_EXCL;

// Establish mode, we normally make the file write-only
//
   if ( bbcp_Config.Options &  bbcp_RTCSNK
   && !(bbcp_Config.Options & (bbcp_RTCHIDE|bbcp_XPIPE)))
      Mode = bbcp_Config.Mode|S_IWUSR|S_ISUID;

// Tell the user what we are bout to do
//
   if (bbcp_Config.Options & bbcp_BLAB | bbcp_Config.Progint)
      if (bbcp_Config.Options & bbcp_APPEND) 
         {char buff[32];
          sprintf(buff, "%lld", startoff);
          bbcp_Fmsg("RecvFile","Appending to",Path,"at offset",buff);
         }
         else bbcp_Fmsg("RecvFile", "Creating", Path);
      else DEBUG("Receiving " <<fp->pathname <<" as " <<Path <<" offset=" <<startoff);

// Receive the file in a sub-process so that we don't muck with this one
//
   if ((Child[0] = bbcp_OS.Fork()) < 0)
      return bbcp_Emsg("RecvFile", errno, "forking to create", Path);
   if (Child[0]) 
      {char buff[128];
       Parent_Monitor.Start(0,Remote);
       DEBUG("Waiting for child " <<Child[0] <<" to finish");
       retc = bbcp_OS.Waitpid(Child);
       Parent_Monitor.Stop();
       if (bbcp_Config.Options & bbcp_BLAB)
          write(STDERR_FILENO, buff, Usage("Target", buff, sizeof(buff)));
       return retc;
      }

/*******************************************************************************
   (net)->data_link[i]->BPool->CStage[1]->CStage[0]->CPool->outFile->(file)
*******************************************************************************/

// Set Concurrency
//
   bbcp_Thread_MT(bbcp_Config.MTLevel);

// Request direct I/O if so wanted
//
   if (bbcp_Config.Options & bbcp_ODIO) {fp->FSys()->DirectIO(1);
       DEBUG("Direct output requested.");}

// Open the file and set the starting offset
//
   Elapsed_Timer.Start();
   if (!(outFile = fp->FSys()->Open(Path, oflag, Mode, Args)))
      return bbcp_Emsg("RecvFile", errno, Act, Path);
   if (startoff && ((retc = outFile->Seek(startoff)) < 0))
      return bbcp_Emsg("RecvFile",retc,"setting write offset for",Path);
   outFile->setSize(fp->Info.size);

// If compression is wanted, set up the compression objects
//
   if (bbcp_Config.Options & bbcp_COMPRESS 
   && !(cxp = setup_CX(0, outFile->ioFD()))) return -ECANCELED;

// Start a thread for each data link we have
//
   for (i = 0; i < dlcount; i++)
       {if ((retc = bbcp_Thread_Start(bbcp_Net2Buff, 
                                (void *)data_link[i], &tid))<0)
           {bbcp_Emsg("RecvFile",retc,"starting net thread for",Path);
            _exit(100);
           }
        link_tid[i] = tid;
        DEBUG("Thread " <<tid <<" assigned to stream " <<i);
       }

// If we are compressing start the sequence thread now
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
      {seqFile = new bbcp_File(Path, 0, 0);
       if ((retc = bbcp_Thread_Start(bbcp_doWrite, (void *)seqFile, &tid))<0)
          {bbcp_Emsg("RecvFile",retc,"starting disk thread for",Path);
           _exit(100);
          }
       link_tid[dlcount++] = tid;
       DEBUG("Thread " <<tid <<" assigned to sequencer as stream " <<i);
      }

// Start the parent process monitor. It is stopped at exit.
//
   Parent_Monitor.Start();

// If a periodic progress message is wanted, start a progress thread
//
   if (bbcp_Config.Progint) 
      {pmp = new bbcp_ProgMon();
       pmp->Start(outFile, cxp, bbcp_Config.Progint, fp->Info.size-startoff);
      }

// Write the whole file
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
           retc = outFile->Write_All(bbcp_APool, 1);
      else retc = outFile->Write_All(bbcp_BPool, bbcp_Config.Streams);
   DEBUG("File write ended; rc=" <<retc);

// Wait for the expansion thread to end
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
      {if (tretc = (long)bbcp_Thread_Wait(cxp->TID)) retc = 128;
       DEBUG("File expansion ended; rc=" <<tretc);
      }

// Kill the progress monitor
//
   if (pmp) 
      {DEBUG("Deleting progress monitor");
       delete pmp;
      }

// Make sure each thread has terminated normally
//
   for (i = 0; i < dlcount; i++)
       {if (tretc = (long)bbcp_Thread_Wait(link_tid[i])) retc = 128;
        DEBUG("Thread " <<link_tid[i] <<" stream " <<i <<" ended; rc=" <<tretc);
       }

// Make sure that all of the bytes were transfered
//
   if (!retc && strncmp(Path, "/dev/null/", 10))
      {bbcp_FileInfo Info;
       if ((retc = fp->FSys()->Stat(Path, &Info)) < 0)
          {retc = -retc;
           bbcp_Emsg("RecvFile", retc, "finding", Path);
          }
          else if (Info.size != fp->Info.size && Info.mode
               &&  !(bbcp_Config.Options & bbcp_NOFSZCHK))
                  {const char *What = (Info.size < fp->Info.size
                                    ?  "Not all" : "Too much");
                   retc = 29;
                   bbcp_Fmsg("RecvFile",What,"data was transfered for",Path);
                   DEBUG("src size=" <<fp->Info.size <<" snk size=" <<Info.size);
                  }
      } DEBUG("Outfile " <<Path <<" closed");

// Report detailed I/O stats, if so wanted
//
   Elapsed_Timer.Stop();
   if (!retc && bbcp_Config.Options & bbcp_VERBOSE)
      {double ttime;
       Elapsed_Timer.Report(ttime);
       Report(ttime, fp, outFile, cxp);
      }

// All done
//
   Parent_Monitor.Stop();
                delete outFile;
   if (cxp)     delete(cxp);
   if (seqFile) delete(seqFile);
   retc = fp->Finalize(retc);
   close(1); close(2);
   DEBUG("Process " <<getpid() <<" exiting with rc=" <<retc);
   exit(retc);
   return(retc);  // some compilers insist on a return in int functions
}
Пример #4
0
int bbcp_Node::SendFile(bbcp_FileSpec *fp)
{
   const char *Act = "opening";
   int i, retc, tretc = 0, Mode = 0;
   pid_t Child[2] = {0,0};
   bbcp_File *inFile;
   bbcp_ProcMon *TLimit = 0;
   bbcp_ZCX *cxp;
   pthread_t tid, link_tid[BBCP_MAXSTREAMS+1];

// Set open options (check for pipes)
//
   if (bbcp_Config.Options & bbcp_XPIPE)
      {if (fp->Info.Otype == 'p') Mode = S_IFIFO;
          else Act = "running";
      }

// Send the file in a sub-process so that we don't muck with this one
//
   DEBUG("Sending file " <<fp->targpath <<"; offset=" <<fp->targetsz);
   if ((Child[0] = bbcp_OS.Fork()) < 0)
      return bbcp_Emsg("SendFile", errno, "forking to send", fp->pathname);
   if (Child[0])
      {char buff[128];
       Parent_Monitor.Start();
       retc = bbcp_OS.Waitpid(Child);
       Parent_Monitor.Stop();
       if (bbcp_Config.Options & bbcp_BLAB)
          write(STDERR_FILENO, buff, Usage("Source", buff, sizeof(buff)));
       return retc;
      }

/*******************************************************************************
    (file)->inFile->CPool->CStage[0]->CStage[1]->BPool->data_link[i]->(net)
*******************************************************************************/

// Set Concurrency
//
   bbcp_Thread_MT(bbcp_Config.MTLevel);

// Request direct I/O if so wanted
//
   if (bbcp_Config.Options & bbcp_IDIO) {fp->FSys()->DirectIO(1);
       DEBUG("Direct input requested.");}

// Open the input file and set starting offset
//
   if (!(inFile = fp->FSys()->Open(fp->pathname,O_RDONLY,Mode,fp->fileargs)))
      {bbcp_Emsg("SendFile", errno, Act, fp->pathname);
       exit(2);
      }
   if (fp->targetsz && ((retc = inFile->Seek(fp->targetsz)) < 0))
      return bbcp_Emsg("SendFile",retc,"setting read offset for",fp->pathname);

// If compression is wanted, set up the compression objects
//
   if (bbcp_Config.Options & bbcp_COMPRESS 
   && !(cxp = setup_CX(1, inFile->ioFD()))) return -ECANCELED;

// Start a thread for each data link we have
//
   for (i = 0; i < dlcount; i++)
       {if ((retc = bbcp_Thread_Start(bbcp_Buff2Net, 
                                (void *)data_link[i], &tid))<0)
           {bbcp_Emsg("SendFile",retc,"starting net thread for",fp->pathname);
            _exit(100);
           }
        link_tid[i] = tid;
        if (i >= iocount) {DEBUG("Thread " <<tid <<" assigned to data clocker");}
           else {DEBUG("Thread " <<tid <<" assigned to stream " <<i);}
       }

// Start the parent monitor
//
   Parent_Monitor.Start();

// Start the Transfer Time Limit
//
   if (bbcp_Config.TimeLimit)
      {TLimit = new bbcp_ProcMon();
       TLimit->Start(bbcp_Config.TimeLimit, &bbcp_BPool);
      }

// Read the whole file
//
   if (bbcp_Config.Options & bbcp_COMPRESS) retc=inFile->Read_All(bbcp_APool,1);
      else retc = inFile->Read_All(bbcp_BPool, bbcp_Config.Bfact);
   DEBUG("File read ended; rc=" <<retc);

// Wait for compression thread to end
//
   if (bbcp_Config.Options & bbcp_COMPRESS)
      {if (tretc = (long)bbcp_Thread_Wait(cxp->TID)) retc = 128;
       DEBUG("File compression ended; rc=" <<tretc);
       delete cxp;
      }

// Make sure each link thread has terminated normally.
//
   for (i = 0; i < iocount; i++)
       {if (tretc = (long)bbcp_Thread_Wait(link_tid[i])) retc = 128;
        DEBUG("Thread " <<link_tid[i] <<" stream " <<i <<" ended; rc=" <<tretc);
       }

// All done
//
   if (TLimit) delete TLimit;
   Parent_Monitor.Stop();
   delete inFile;
   close(1); close(2);
   DEBUG("Process " <<getpid() <<" exiting with rc=" <<retc);
   exit(retc);
   return(retc);  // some compilers insist on a return in int functions
}
Пример #5
0
int  bbcp_Thread_Run(void *(*proc)(void *), void *arg, pthread_t *tid)
     {int retc = bbcp_Thread_Start(proc, arg, tid);
      if (!retc) pthread_detach(*tid);
      return retc;
     }