llvfile.cpp

Go to the documentation of this file.
00001 
00032 #include "linden_common.h"
00033 
00034 #include "llvfile.h"
00035 
00036 #include "llerror.h"
00037 #include "llthread.h"
00038 #include "llvfs.h"
00039 
00040 const S32 LLVFile::READ                 = 0x00000001;
00041 const S32 LLVFile::WRITE                = 0x00000002;
00042 const S32 LLVFile::READ_WRITE   = 0x00000003;  // LLVFile::READ & LLVFile::WRITE
00043 const S32 LLVFile::APPEND               = 0x00000006;  // 0x00000004 & LLVFile::WRITE
00044 
00045 //----------------------------------------------------------------------------
00046 LLVFSThread* LLVFile::sVFSThread = NULL;
00047 BOOL LLVFile::sAllocdVFSThread = FALSE;
00048 //----------------------------------------------------------------------------
00049 
00050 //============================================================================
00051 
00052 LLVFile::LLVFile(LLVFS *vfs, const LLUUID &file_id, const LLAssetType::EType file_type, S32 mode)
00053 {
00054         mFileType =     file_type;
00055 
00056         mFileID =       file_id;
00057         mPosition = 0;
00058         mMode =         mode;
00059         mVFS =          vfs;
00060 
00061         mBytesRead = 0;
00062         mHandle = LLVFSThread::nullHandle();
00063         mPriority = 128.f;
00064 
00065         mVFS->incLock(mFileID, mFileType, VFSLOCK_OPEN);
00066 }
00067 
00068 LLVFile::~LLVFile()
00069 {
00070         if (!isReadComplete())
00071         {
00072                 if (mHandle != LLVFSThread::nullHandle())
00073                 {
00074                         if (!(mMode & LLVFile::WRITE))
00075                         {
00076                                 //llwarns << "Destroying LLVFile with pending async read/write, aborting..." << llendl;
00077                                 sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_ABORT);
00078                         }
00079                         else // WRITE
00080                         {
00081                                 sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE);
00082                         }
00083                 }
00084         }
00085         mVFS->decLock(mFileID, mFileType, VFSLOCK_OPEN);
00086 }
00087 
00088 BOOL LLVFile::read(U8 *buffer, S32 bytes, BOOL async, F32 priority)
00089 {
00090         if (! (mMode & READ))
00091         {
00092                 llwarns << "Attempt to read from file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
00093                 return FALSE;
00094         }
00095 
00096         if (mHandle != LLVFSThread::nullHandle())
00097         {
00098                 llwarns << "Attempt to read from vfile object " << mFileID << " with pending async operation" << llendl;
00099                 return FALSE;
00100         }
00101         mPriority = priority;
00102         
00103         BOOL success = TRUE;
00104 
00105         // We can't do a read while there are pending async writes
00106         waitForLock(VFSLOCK_APPEND);
00107         
00108         // *FIX: (???)
00109         if (async)
00110         {
00111                 mHandle = sVFSThread->read(mVFS, mFileID, mFileType, buffer, mPosition, bytes, threadPri());
00112         }
00113         else
00114         {
00115                 // We can't do a read while there are pending async writes on this file
00116                 mBytesRead = sVFSThread->readImmediate(mVFS, mFileID, mFileType, buffer, mPosition, bytes);
00117                 mPosition += mBytesRead;
00118                 if (! mBytesRead)
00119                 {
00120                         success = FALSE;
00121                 }
00122         }
00123 
00124         return success;
00125 }
00126 
00127 //static
00128 U8* LLVFile::readFile(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, S32* bytes_read)
00129 {
00130         U8 *data;
00131         LLVFile file(vfs, uuid, type, LLVFile::READ);
00132         S32 file_size = file.getSize();
00133         if (file_size == 0)
00134         {
00135                 // File is empty.
00136                 data = NULL;
00137         }
00138         else
00139         {
00140                 data = new U8[file_size];
00141                 file.read(data, file_size);     /* Flawfinder: ignore */ 
00142                 
00143                 if (file.getLastBytesRead() != (S32)file_size)
00144                 {
00145                         delete[] data;
00146                         data = NULL;
00147                         file_size = 0;
00148                 }
00149         }
00150         if (bytes_read)
00151         {
00152                 *bytes_read = file_size;
00153         }
00154         return data;
00155 }
00156         
00157 void LLVFile::setReadPriority(const F32 priority)
00158 {
00159         mPriority = priority;
00160         if (mHandle != LLVFSThread::nullHandle())
00161         {
00162                 sVFSThread->setPriority(mHandle, threadPri());
00163         }
00164 }
00165 
00166 BOOL LLVFile::isReadComplete()
00167 {
00168         BOOL res = TRUE;
00169         if (mHandle != LLVFSThread::nullHandle())
00170         {
00171                 LLVFSThread::Request* req = (LLVFSThread::Request*)sVFSThread->getRequest(mHandle);
00172                 LLVFSThread::status_t status = req->getStatus();
00173                 if (status == LLVFSThread::STATUS_COMPLETE)
00174                 {
00175                         mBytesRead = req->getBytesRead();
00176                         mPosition += mBytesRead;
00177                         sVFSThread->completeRequest(mHandle);
00178                         mHandle = LLVFSThread::nullHandle();
00179                 }
00180                 else
00181                 {
00182                         res = FALSE;
00183                 }
00184         }
00185         return res;
00186 }
00187 
00188 S32 LLVFile::getLastBytesRead()
00189 {
00190         return mBytesRead;
00191 }
00192 
00193 BOOL LLVFile::eof()
00194 {
00195         return mPosition >= getSize();
00196 }
00197 
00198 BOOL LLVFile::write(const U8 *buffer, S32 bytes)
00199 {
00200         if (! (mMode & WRITE))
00201         {
00202                 llwarns << "Attempt to write to file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
00203         }
00204         if (mHandle != LLVFSThread::nullHandle())
00205         {
00206                 llerrs << "Attempt to write to vfile object " << mFileID << " with pending async operation" << llendl;
00207                 return FALSE;
00208         }
00209         BOOL success = TRUE;
00210         
00211         // *FIX: allow async writes? potential problem wit mPosition...
00212         if (mMode == APPEND) // all appends are async (but WRITEs are not)
00213         {       
00214                 U8* writebuf = new U8[bytes];
00215                 memcpy(writebuf, buffer, bytes);
00216                 S32 offset = -1;
00217                 mHandle = sVFSThread->write(mVFS, mFileID, mFileType,
00218                                                                         writebuf, offset, bytes,
00219                                                                         LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_AUTO_DELETE);
00220                 mHandle = LLVFSThread::nullHandle(); // FLAG_AUTO_COMPLETE means we don't track this
00221         }
00222         else
00223         {
00224                 // We can't do a write while there are pending reads or writes on this file
00225                 waitForLock(VFSLOCK_READ);
00226                 waitForLock(VFSLOCK_APPEND);
00227 
00228                 S32 pos = (mMode & APPEND) == APPEND ? -1 : mPosition;
00229 
00230                 S32 wrote = sVFSThread->writeImmediate(mVFS, mFileID, mFileType, (U8*)buffer, pos, bytes);
00231 
00232                 mPosition += wrote;
00233                 
00234                 if (wrote < bytes)
00235                 {       
00236                         llwarns << "Tried to write " << bytes << " bytes, actually wrote " << wrote << llendl;
00237 
00238                         success = FALSE;
00239                 }
00240         }
00241         return success;
00242 }
00243 
00244 //static
00245 BOOL LLVFile::writeFile(const U8 *buffer, S32 bytes, LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type)
00246 {
00247         LLVFile file(vfs, uuid, type, LLVFile::WRITE);
00248         file.setMaxSize(bytes);
00249         return file.write(buffer, bytes);
00250 }
00251 
00252 BOOL LLVFile::seek(S32 offset, S32 origin)
00253 {
00254         if (mMode == APPEND)
00255         {
00256                 llwarns << "Attempt to seek on append-only file" << llendl;
00257                 return FALSE;
00258         }
00259 
00260         if (-1 == origin)
00261         {
00262                 origin = mPosition;
00263         }
00264 
00265         S32 new_pos = origin + offset;
00266 
00267         S32 size = getSize(); // Calls waitForLock(VFSLOCK_APPEND)
00268 
00269         if (new_pos > size)
00270         {
00271                 llwarns << "Attempt to seek past end of file" << llendl;
00272 
00273                 mPosition = size;
00274                 return FALSE;
00275         }
00276         else if (new_pos < 0)
00277         {
00278                 llwarns << "Attempt to seek past beginning of file" << llendl;
00279 
00280                 mPosition = 0;
00281                 return FALSE;
00282         }
00283 
00284         mPosition = new_pos;
00285         return TRUE;
00286 }
00287 
00288 S32 LLVFile::tell() const
00289 {
00290         return mPosition;
00291 }
00292 
00293 S32 LLVFile::getSize()
00294 {
00295         waitForLock(VFSLOCK_APPEND);
00296         S32 size = mVFS->getSize(mFileID, mFileType);
00297 
00298         return size;
00299 }
00300 
00301 S32 LLVFile::getMaxSize()
00302 {
00303         S32 size = mVFS->getMaxSize(mFileID, mFileType);
00304 
00305         return size;
00306 }
00307 
00308 BOOL LLVFile::setMaxSize(S32 size)
00309 {
00310         if (! (mMode & WRITE))
00311         {
00312                 llwarns << "Attempt to change size of file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
00313 
00314                 return FALSE;
00315         }
00316 
00317         if (!mVFS->checkAvailable(size))
00318         {
00319                 LLFastTimer t(LLFastTimer::FTM_VFILE_WAIT);
00320                 S32 count = 0;
00321                 while (sVFSThread->getPending() > 1000)
00322                 {
00323                         if (count % 100 == 0)
00324                         {
00325                                 llinfos << "VFS catching up... Pending: " << sVFSThread->getPending() << llendl;
00326                         }
00327                         if (sVFSThread->isPaused())
00328                         {
00329                                 sVFSThread->update(0);
00330                         }
00331                         ms_sleep(10);
00332                 }
00333         }
00334         return mVFS->setMaxSize(mFileID, mFileType, size);
00335 }
00336 
00337 BOOL LLVFile::rename(const LLUUID &new_id, const LLAssetType::EType new_type)
00338 {
00339         if (! (mMode & WRITE))
00340         {
00341                 llwarns << "Attempt to rename file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
00342 
00343                 return FALSE;
00344         }
00345 
00346         if (mHandle != LLVFSThread::nullHandle())
00347         {
00348                 llwarns << "Renaming file with pending async read" << llendl;
00349         }
00350 
00351         waitForLock(VFSLOCK_READ);
00352         waitForLock(VFSLOCK_APPEND);
00353 
00354         // we need to release / replace our own lock
00355         // since the renamed file will inherit locks from the new name
00356         mVFS->decLock(mFileID, mFileType, VFSLOCK_OPEN);
00357         mVFS->renameFile(mFileID, mFileType, new_id, new_type);
00358         mVFS->incLock(new_id, new_type, VFSLOCK_OPEN);
00359         
00360         mFileID = new_id;
00361         mFileType = new_type;
00362 
00363         return TRUE;
00364 }
00365 
00366 BOOL LLVFile::remove()
00367 {
00368 //      llinfos << "Removing file " << mFileID << llendl;
00369         
00370         if (! (mMode & WRITE))
00371         {
00372                 // Leaving paranoia warning just because this should be a very infrequent
00373                 // operation.
00374                 llwarns << "Remove file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
00375         }
00376 
00377         if (mHandle != LLVFSThread::nullHandle())
00378         {
00379                 llwarns << "Removing file with pending async read" << llendl;
00380         }
00381         
00382         // why not seek back to the beginning of the file too?
00383         mPosition = 0;
00384 
00385         waitForLock(VFSLOCK_READ);
00386         waitForLock(VFSLOCK_APPEND);
00387         mVFS->removeFile(mFileID, mFileType);
00388 
00389         return TRUE;
00390 }
00391 
00392 // static
00393 void LLVFile::initClass(LLVFSThread* vfsthread)
00394 {
00395         if (!vfsthread)
00396         {
00397                 if (LLVFSThread::sLocal != NULL)
00398                 {
00399                         vfsthread = LLVFSThread::sLocal;
00400                 }
00401                 else
00402                 {
00403                         vfsthread = new LLVFSThread();
00404                         sAllocdVFSThread = TRUE;
00405                 }
00406         }
00407         sVFSThread = vfsthread;
00408 }
00409 
00410 // static
00411 void LLVFile::cleanupClass()
00412 {
00413         if (sAllocdVFSThread)
00414         {
00415                 delete sVFSThread;
00416         }
00417         sVFSThread = NULL;
00418 }
00419 
00420 bool LLVFile::isLocked(EVFSLock lock)
00421 {
00422         return mVFS->isLocked(mFileID, mFileType, lock) ? true : false;
00423 }
00424 
00425 void LLVFile::waitForLock(EVFSLock lock)
00426 {
00427         LLFastTimer t(LLFastTimer::FTM_VFILE_WAIT);
00428         // spin until the lock clears
00429         while (isLocked(lock))
00430         {
00431                 if (sVFSThread->isPaused())
00432                 {
00433                         sVFSThread->update(0);
00434                 }
00435                 ms_sleep(1);
00436         }
00437 }

Generated on Fri May 16 08:33:01 2008 for SecondLife by  doxygen 1.5.5