// . get the fd of this file // . if it was closed by us we reopen it // . may re-open a virtual fd whose real fd was closed // . if we hit our max # of real fds allowed we'll have to close // the least used of those so we can open this one // . return -2 if never been opened // . return -1 on other errors // . otherwise, return the file descriptor int File::getfd () { // if m_vfd is -1 it's never been opened if ( m_vfd < 0 ) { g_errno = EBADENGINEER; log(LOG_LOGIC,"disk: getfd: Must call open() first."); char *xx=NULL; *xx=0; return -2; } // . sanity check // . no caller should call open/getfd after unlink was queued for thred //if ( m_gone ) { char *xx = NULL; *xx = 0; } // get the real fd from the virtual fd int fd = s_fds [ m_vfd ]; // return true if it's already opened if ( fd >= 0 ) { // debug msg log(LOG_DEBUG,"disk: Opened vfd #%li of %li.", (long)m_vfd,(long)s_fds[m_vfd]); // but update the timestamp to reduce chance it closes on us //s_timestamps [ m_vfd ] = getTime(); s_timestamps [ m_vfd ] = gettimeofdayInMillisecondsLocal(); return fd; } // if fd is -2 it's marked as available if ( fd != -1 ) { g_errno = EBADENGINEER; log (LOG_LOGIC, "disk: getfd: fd is available?!?!" ); return -2; } // . a real fd of -1 means it's been closed and we gotta reopen it // . we have to close someone if we don't have enough room while ( s_numOpenFiles >= s_maxNumOpenFiles ) if ( ! closeLeastUsed() ) return -1; // what was the filename/mode of this timed-out fd? //char *filename = s_filenames [ m_vfd ]; // time the calls to open just in case they are hurting us long long t1 = -1LL; // . re-open the sleeping file descriptor // . if a rename thread was queued or spawned, try old guy first //if ( m_oldFilename[0] ) { // t1 = gettimeofdayInMilliseconds(); // fd = ::open ( m_oldFilename , m_flags , m_permissions ); //} // then try to open the new name if ( fd == -1 ) { t1 = gettimeofdayInMilliseconds(); retry7: fd = ::open ( m_filename , m_flags , m_permissions ); // valgrind if ( fd == -1 && errno == EINTR ) goto retry7; // 0 means stdout, right? why am i seeing it get assigned??? if ( fd == 0 ) log("disk: Got fd of 0 when opening %s.",m_filename); if ( fd == 0 ) fd = ::open ( m_filename , m_flags , m_permissions ); if ( fd == 0 ) log("disk: Got fd of 0 when opening2 %s.",m_filename); // . now inc that count in case there was someone reading on // that fd right before it was closed and we got it // . ::close() call can now happen in a thread, so we // need to inc this guy here now, too // . so when that read returns it will know to re-do // . this should really be named s_openCounts!! if ( fd >= 0 ) s_closeCounts [ fd ]++; // . we now record this // . that way if our fd gets closed in closeLeastUsed() or // in close1_r() due to a rename/unlink then we know it! // . this fixes a race condition of closeCounts in Threads.cpp // where we did not know that the fd had been stolen from // us and assigned to another file because our close1_r() // had called ::close() on our fd and our closeCount algo // failed us. see the top of this file for more description // into this bug fix. m_closeCount = s_closeCounts[fd]; } if ( t1 >= 0 ) { long long dt = gettimeofdayInMilliseconds() - t1 ; if ( dt > 1 ) log(LOG_INFO, "disk: call to open(%s) blocked for " "%lli ms.",m_filename,dt); } // copy errno to g_errno if ( fd == -1 ) { g_errno = errno; log("disk: error open(%s) : %s",m_filename,strerror(g_errno)); return -1; } // we're another open file s_numOpenFiles++; // set this file descriptor, the other stuff remains the same s_fds [ m_vfd ] = fd; // 0 means stdout, right? why am i seeing it get assigned??? if ( fd == 0 ) log("disk: Found fd of 0 when opening %s.",m_filename); // reset s_writing [ m_vfd ] = 0; s_unlinking [ m_vfd ] = 0; // update the time stamp s_timestamps [ m_vfd ] = gettimeofdayInMillisecondsLocal(); return fd; }
// . get the fd of this file // . if it was closed by us we reopen it // . may re-open a virtual fd whose real fd was closed // . if we hit our max # of real fds allowed we'll have to close // the least used of those so we can open this one // . return -2 if never been opened // . return -1 on other errors // . otherwise, return the file descriptor int File::getfd () { // if m_vfd is -1 it's never been opened if ( ! m_calledOpen ) { // m_vfd < 0 ) { g_errno = EBADENGINEER; log(LOG_LOGIC,"disk: getfd: Must call open() first."); char *xx=NULL; *xx=0; return -2; } // if someone closed our fd, why didn't our m_fd get set to -1 ??!?!?!! if ( m_fd >= 0 && m_closeCount != s_closeCounts[m_fd] ) { log(LOG_DEBUG,"disk: invalidating existing fd %i " "for %s this=0x%"PTRFMT" ccSaved=%i ccNow=%i", (int)m_fd,getFilename(),(PTRTYPE)this, (int)m_closeCount, (int)s_closeCounts[m_fd]); m_fd = -1; } // . sanity check // . no caller should call open/getfd after unlink was queued for thred //if ( m_gone ) { char *xx = NULL; *xx = 0; } // get the real fd from the virtual fd //int fd = s_fds [ m_vfd ]; // return true if it's already opened if ( m_fd >= 0 ) { // debug msg if ( g_conf.m_logDebugDisk ) log(LOG_DEBUG,"disk: returning existing fd %i for %s " "this=0x%"PTRFMT" ccSaved=%i ccNow=%i", (int)m_fd,getFilename(),(PTRTYPE)this, (int)m_closeCount, (int)s_closeCounts[m_fd]); if ( m_fd >= MAX_NUM_FDS ) { char *xx=NULL;*xx=0; } // but update the timestamp to reduce chance it closes on us //s_timestamps [ m_vfd ] = getTime(); s_timestamps [ m_fd ] = gettimeofdayInMillisecondsLocal(); return m_fd; } // if fd is -2 it's marked as available // if ( fd != -1 ) { // g_errno = EBADENGINEER; // log (LOG_LOGIC, "disk: getfd: fd is available?!?!" ); // return -2; // } // . a real fd of -1 means it's been closed and we gotta reopen it // . we have to close someone if we don't have enough room while ( s_numOpenFiles >= s_maxNumOpenFiles ) { if ( g_conf.m_logDebugDisk ) sanityCheck(); if ( ! closeLeastUsed() ) return -1; if ( g_conf.m_logDebugDisk ) sanityCheck(); } // what was the filename/mode of this timed-out fd? //char *filename = s_filenames [ m_vfd ]; // time the calls to open just in case they are hurting us int64_t t1 = -1LL; // . re-open the sleeping file descriptor // . if a rename thread was queued or spawned, try old guy first //if ( m_oldFilename[0] ) { // t1 = gettimeofdayInMilliseconds(); // fd = ::open ( m_oldFilename , m_flags , m_permissions ); //} int fd = -1; // then try to open the new name if ( fd == -1 ) { t1 = gettimeofdayInMilliseconds(); retry7: fd = ::open ( getFilename() , m_flags,getFileCreationFlags()); // valgrind if ( fd == -1 && errno == EINTR ) goto retry7; // 0 means stdout, right? why am i seeing it get assigned??? if ( fd == 0 ) log("disk: Got fd of 0 when opening %s.", getFilename()); if ( fd == 0 ) fd=::open(getFilename(),m_flags,getFileCreationFlags()); if ( fd == 0 ) log("disk: Got fd of 0 when opening2 %s.", getFilename()); if ( fd >= MAX_NUM_FDS ) log("disk: got fd of %i out of bounds 1 of %i", (int)fd,(int)MAX_NUM_FDS); // if we got someone else's fd that called close1_r() in a // thread but did not have time to call close2() to fix // up these member vars, then do it here. close2() will // see that s_filePtrs[fd] does not equal the file ptr any more // and it will not update s_numOpenFiles in that case. if ( fd >= 0 && s_open [ fd ] ) { File *f = s_filePtrs [ fd ]; if ( g_conf.m_logDebugDisk ) log("disk: swiping fd %i from %s before " "his close thread returned " "this=0x%"PTRFMT, fd, f->getFilename(), (PTRTYPE)f); // he only incs/decs his counters if he owns it so in // close2() so dec this global counter here s_numOpenFiles--; s_open[fd] = 0; s_filePtrs[fd] = NULL; if ( g_conf.m_logDebugDisk ) sanityCheck(); } // sanity. how can we get an fd already opened? // because it was closed in a thread in close1_r() if ( fd >= 0 && s_open[fd] ) { char *xx=NULL;*xx=0; } // . now inc that count in case there was someone reading on // that fd right before it was closed and we got it // . ::close() call can now happen in a thread, so we // need to inc this guy here now, too // . so when that read returns it will know to re-do // . this should really be named s_openCounts!! if ( fd >= 0 ) s_closeCounts [ fd ]++; // . we now record this // . that way if our fd gets closed in closeLeastUsed() or // in close1_r() due to a rename/unlink then we know it! // . this fixes a race condition of closeCounts in Threads.cpp // where we did not know that the fd had been stolen from // us and assigned to another file because our close1_r() // had called ::close() on our fd and our closeCount algo // failed us. see the top of this file for more description // into this bug fix. m_closeCount = s_closeCounts[fd]; } if ( t1 >= 0 ) { int64_t dt = gettimeofdayInMilliseconds() - t1 ; if ( dt > 1 ) log(LOG_INFO, "disk: call to open(%s) blocked for " "%"INT64" ms.",getFilename(),dt); } // copy errno to g_errno if ( fd <= -1 ) { g_errno = errno; log("disk: error open(%s) : %s fd %i", getFilename(),strerror(g_errno),(int)fd); return -1; } if ( g_conf.m_logDebugDisk ) sanityCheck(); // we're another open file s_numOpenFiles++; // debug log if ( g_conf.m_logDebugDisk ) log("disk: opened1 fd %i for %s #openfiles=%i this=0x%"PTRFMT, (int)fd,getFilename(),(int)s_numOpenFiles,(PTRTYPE)this); // set this file descriptor, the other stuff remains the same //s_fds [ m_vfd ] = fd; m_fd = fd; // 0 means stdout, right? why am i seeing it get assigned??? if ( fd == 0 ) log("disk: Found fd of 0 when opening %s.",getFilename()); // reset s_writing [ fd ] = 0; s_unlinking [ fd ] = 0; // update the time stamp s_timestamps [ fd ] = gettimeofdayInMillisecondsLocal(); s_open [ fd ] = true; s_filePtrs [ fd ] = this; if ( g_conf.m_logDebugDisk ) sanityCheck(); // add file to linked list of active files //addFileToLinkedList ( this ); return fd; }