summaryrefslogtreecommitdiff
path: root/indra/llfilesystem/lldiskcache.cpp
diff options
context:
space:
mode:
authorCallum Prentice <callum@gmail.com>2020-09-17 09:45:06 -0700
committerCallum Prentice <callum@gmail.com>2020-09-17 09:45:06 -0700
commitd9448c6f52218146113d1d5c5ca4c4d5f01dc5cf (patch)
treea264e71da59ef1a0ecf78e0a2cba0bb3bdc3ff1c /indra/llfilesystem/lldiskcache.cpp
parent20b50f99c89271518ae37ade0ef0866167070c80 (diff)
The folder where the disk cache lives was originally renamed from llvfs to llcache but @henri's suggestion that that doesn't reflect the other files in the same place and it should be llfilesystem is a good one so I changed it over
Diffstat (limited to 'indra/llfilesystem/lldiskcache.cpp')
-rw-r--r--indra/llfilesystem/lldiskcache.cpp387
1 files changed, 387 insertions, 0 deletions
diff --git a/indra/llfilesystem/lldiskcache.cpp b/indra/llfilesystem/lldiskcache.cpp
new file mode 100644
index 0000000000..af93049e07
--- /dev/null
+++ b/indra/llfilesystem/lldiskcache.cpp
@@ -0,0 +1,387 @@
+/**
+ * @file lldiskcache.cpp
+ * @brief Implementation of virtual file
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "lldiskcache.h"
+
+#include "llerror.h"
+#include "llthread.h"
+#include "lltimer.h"
+#include "llfasttimer.h"
+#include "llmemory.h"
+
+#include <fstream>
+#include "lldir.h"
+
+const S32 LLDiskCache::READ = 0x00000001;
+const S32 LLDiskCache::WRITE = 0x00000002;
+const S32 LLDiskCache::READ_WRITE = 0x00000003; // LLDiskCache::READ & LLDiskCache::WRITE
+const S32 LLDiskCache::APPEND = 0x00000006; // 0x00000004 & LLDiskCache::WRITE
+
+static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait");
+
+LLDiskCache::LLDiskCache(const LLUUID &file_id, const LLAssetType::EType file_type, S32 mode)
+{
+ mFileType = file_type;
+ mFileID = file_id;
+ mPosition = 0;
+ mBytesRead = 0;
+ mReadComplete = FALSE;
+ mMode = mode;
+}
+
+LLDiskCache::~LLDiskCache()
+{
+}
+
+const std::string assetTypeToString(LLAssetType::EType at)
+{
+ /**
+ * Make use of the C++17 (or is it 14) feature that allows
+ * for inline initialization of an std::map<>
+ */
+ typedef std::map<LLAssetType::EType, std::string> asset_type_to_name_t;
+ asset_type_to_name_t asset_type_to_name =
+ {
+ { LLAssetType::AT_TEXTURE, "TEXTURE" },
+ { LLAssetType::AT_SOUND, "SOUND" },
+ { LLAssetType::AT_CALLINGCARD, "CALLINGCARD" },
+ { LLAssetType::AT_LANDMARK, "LANDMARK" },
+ { LLAssetType::AT_SCRIPT, "SCRIPT" },
+ { LLAssetType::AT_CLOTHING, "CLOTHING" },
+ { LLAssetType::AT_OBJECT, "OBJECT" },
+ { LLAssetType::AT_NOTECARD, "NOTECARD" },
+ { LLAssetType::AT_CATEGORY, "CATEGORY" },
+ { LLAssetType::AT_LSL_TEXT, "LSL_TEXT" },
+ { LLAssetType::AT_LSL_BYTECODE, "LSL_BYTECODE" },
+ { LLAssetType::AT_TEXTURE_TGA, "TEXTURE_TGA" },
+ { LLAssetType::AT_BODYPART, "BODYPART" },
+ { LLAssetType::AT_SOUND_WAV, "SOUND_WAV" },
+ { LLAssetType::AT_IMAGE_TGA, "IMAGE_TGA" },
+ { LLAssetType::AT_IMAGE_JPEG, "IMAGE_JPEG" },
+ { LLAssetType::AT_ANIMATION, "ANIMATION" },
+ { LLAssetType::AT_GESTURE, "GESTURE" },
+ { LLAssetType::AT_SIMSTATE, "SIMSTATE" },
+ { LLAssetType::AT_LINK, "LINK" },
+ { LLAssetType::AT_LINK_FOLDER, "LINK_FOLDER" },
+ { LLAssetType::AT_MARKETPLACE_FOLDER, "MARKETPLACE_FOLDER" },
+ { LLAssetType::AT_WIDGET, "WIDGET" },
+ { LLAssetType::AT_PERSON, "PERSON" },
+ { LLAssetType::AT_MESH, "MESH" },
+ { LLAssetType::AT_SETTINGS, "SETTINGS" },
+ { LLAssetType::AT_UNKNOWN, "UNKNOWN" }
+ };
+
+ asset_type_to_name_t::iterator iter = asset_type_to_name.find(at);
+ if (iter != asset_type_to_name.end())
+ {
+ return iter->second;
+ }
+
+ return std::string("UNKNOWN");
+}
+
+const std::string idToFilepath(const std::string id, LLAssetType::EType at)
+{
+ /**
+ * For the moment this is just {UUID}_{ASSET_TYPE}.txt but of
+ * course, will be greatly expanded upon
+ */
+ std::ostringstream ss;
+ ss << "00cache_";
+ ss << id;
+ ss << "_";
+ ss << assetTypeToString(at);
+ ss << ".txt";
+
+ const std::string filepath = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ss.str());
+
+ return filepath;
+}
+
+// static
+bool LLDiskCache::getExists(const LLUUID &file_id, const LLAssetType::EType file_type)
+{
+ std::string id_str;
+ file_id.toString(id_str);
+ const std::string filename = idToFilepath(id_str, file_type);
+
+ std::ifstream file(filename, std::ios::binary);
+ if (file.is_open())
+ {
+ file.seekg(0, std::ios::end);
+ return file.tellg() > 0;
+ }
+ return false;
+}
+
+// static
+bool LLDiskCache::removeFile(const LLUUID &file_id, const LLAssetType::EType file_type)
+{
+ std::string id_str;
+ file_id.toString(id_str);
+ const std::string filename = idToFilepath(id_str, file_type);
+
+ std::remove(filename.c_str());
+
+ return true;
+}
+
+// static
+bool LLDiskCache::renameFile(const LLUUID &old_file_id, const LLAssetType::EType old_file_type,
+ const LLUUID &new_file_id, const LLAssetType::EType new_file_type)
+{
+ std::string old_id_str;
+ old_file_id.toString(old_id_str);
+ const std::string old_filename = idToFilepath(old_id_str, old_file_type);
+
+ std::string new_id_str;
+ new_file_id.toString(new_id_str);
+ const std::string new_filename = idToFilepath(new_id_str, new_file_type);
+
+ if (std::rename(old_filename.c_str(), new_filename.c_str()))
+ {
+ // We would like to return FALSE here indicating the operation
+ // failed but the original code does not and doing so seems to
+ // break a lot of things so we go with the flow...
+ //return FALSE;
+ }
+
+ return TRUE;
+}
+
+// static
+S32 LLDiskCache::getFileSize(const LLUUID &file_id, const LLAssetType::EType file_type)
+{
+ std::string id_str;
+ file_id.toString(id_str);
+ const std::string filename = idToFilepath(id_str, file_type);
+
+ S32 file_size = 0;
+ std::ifstream file(filename, std::ios::binary);
+ if (file.is_open())
+ {
+ file.seekg(0, std::ios::end);
+ file_size = file.tellg();
+ }
+
+ return file_size;
+}
+
+BOOL LLDiskCache::read(U8 *buffer, S32 bytes, BOOL async, F32 priority)
+{
+ BOOL success = TRUE;
+
+ mReadComplete = FALSE;
+
+ std::string id;
+ mFileID.toString(id);
+ const std::string filename = idToFilepath(id, mFileType);
+
+ std::ifstream file(filename, std::ios::binary);
+ if (file.is_open())
+ {
+ file.seekg(mPosition, std::ios::beg);
+
+ file.read((char*)buffer, bytes);
+
+ if (file)
+ {
+ mBytesRead = bytes;
+ }
+ else
+ {
+ mBytesRead = file.gcount();
+ }
+
+ file.close();
+
+ mPosition += mBytesRead;
+ if (!mBytesRead)
+ {
+ success = FALSE;
+ }
+
+ mReadComplete = TRUE;
+ }
+
+ return success;
+}
+
+BOOL LLDiskCache::isReadComplete()
+{
+ if (mReadComplete)
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+S32 LLDiskCache::getLastBytesRead()
+{
+ return mBytesRead;
+}
+
+BOOL LLDiskCache::eof()
+{
+ return mPosition >= getSize();
+}
+
+BOOL LLDiskCache::write(const U8 *buffer, S32 bytes)
+{
+ std::string id_str;
+ mFileID.toString(id_str);
+ const std::string filename = idToFilepath(id_str, mFileType);
+
+ BOOL success = FALSE;
+
+ if (mMode == APPEND)
+ {
+ std::ofstream ofs(filename, std::ios::app | std::ios::binary);
+ if (ofs)
+ {
+ ofs.write((const char*)buffer, bytes);
+
+ success = TRUE;
+ }
+ }
+ else
+ {
+ std::ofstream ofs(filename, std::ios::binary);
+ if (ofs)
+ {
+ ofs.write((const char*)buffer, bytes);
+
+ mPosition += bytes;
+
+ success = TRUE;
+ }
+ }
+
+ return success;
+}
+
+//static
+BOOL LLDiskCache::writeFile(const U8 *buffer, S32 bytes, const LLUUID &uuid, LLAssetType::EType type)
+{
+ LLDiskCache file(uuid, type, LLDiskCache::WRITE);
+ file.setMaxSize(bytes);
+ return file.write(buffer, bytes);
+}
+
+BOOL LLDiskCache::seek(S32 offset, S32 origin)
+{
+ if (-1 == origin)
+ {
+ origin = mPosition;
+ }
+
+ S32 new_pos = origin + offset;
+
+ S32 size = getSize();
+
+ if (new_pos > size)
+ {
+ LL_WARNS() << "Attempt to seek past end of file" << LL_ENDL;
+
+ mPosition = size;
+ return FALSE;
+ }
+ else if (new_pos < 0)
+ {
+ LL_WARNS() << "Attempt to seek past beginning of file" << LL_ENDL;
+
+ mPosition = 0;
+ return FALSE;
+ }
+
+ mPosition = new_pos;
+ return TRUE;
+}
+
+S32 LLDiskCache::tell() const
+{
+ return mPosition;
+}
+
+S32 LLDiskCache::getSize()
+{
+ return LLDiskCache::getFileSize(mFileID, mFileType);
+}
+
+S32 LLDiskCache::getMaxSize()
+{
+ // offer up a huge size since we don't care what the max is
+ return INT_MAX;
+}
+
+BOOL LLDiskCache::setMaxSize(S32 size)
+{
+ // we don't care what the max size is so we do nothing
+ // and return true to indicate all was okay
+ return TRUE;
+}
+
+BOOL LLDiskCache::rename(const LLUUID &new_id, const LLAssetType::EType new_type)
+{
+ LLDiskCache::renameFile(mFileID, mFileType, new_id, new_type);
+
+ mFileID = new_id;
+ mFileType = new_type;
+
+ return TRUE;
+}
+
+BOOL LLDiskCache::remove()
+{
+ LLDiskCache::removeFile(mFileID, mFileType);
+
+ return TRUE;
+}
+
+// static
+void LLDiskCache::initClass()
+{
+}
+
+// static
+void LLDiskCache::cleanupClass()
+{
+}
+
+bool LLDiskCache::isLocked()
+{
+ // I don't think we care about this test since there is no locking
+ // TODO: remove this function and calling sites?
+ return FALSE;
+}
+
+void LLDiskCache::waitForLock()
+{
+ // TODO: remove this function and calling sites?
+}