added: simplified circular buffer for CFileCache
authorelupus <elupus@xbmc.org>
Thu, 24 Mar 2011 22:30:13 +0000 (23:30 +0100)
committerelupus <elupus@xbmc.org>
Fri, 25 Mar 2011 19:04:25 +0000 (20:04 +0100)
It has less memory requirement than previous system and only uses a single buffer wich removes the need to copy around data between history and future buffers.

project/VS2010Express/XBMC.vcxproj
project/VS2010Express/XBMC.vcxproj.filters
xbmc/filesystem/CacheCircular.cpp [new file with mode: 0644]
xbmc/filesystem/CacheCircular.h [new file with mode: 0644]
xbmc/filesystem/FileCache.cpp
xbmc/filesystem/Makefile.in

index 80d257c..aff795d 100644 (file)
     <ClCompile Include="..\..\xbmc\DynamicDll.cpp" />
     <ClCompile Include="..\..\xbmc\Favourites.cpp" />
     <ClCompile Include="..\..\xbmc\FileItem.cpp" />
+    <ClCompile Include="..\..\xbmc\filesystem\CacheCircular.cpp" />
     <ClCompile Include="..\..\xbmc\FileSystem\iso9660.cpp" />
     <ClCompile Include="..\..\xbmc\FileSystem\ISO9660Directory.cpp" />
     <ClCompile Include="..\..\xbmc\FileSystem\FileUDF.cpp" />
     <ClInclude Include="..\..\xbmc\DynamicDll.h" />
     <ClInclude Include="..\..\xbmc\Favourites.h" />
     <ClInclude Include="..\..\xbmc\FileItem.h" />
+    <ClInclude Include="..\..\xbmc\filesystem\CacheCircular.h" />
     <ClInclude Include="..\..\xbmc\filesystem\Directory.h" />
     <ClInclude Include="..\..\xbmc\filesystem\DirectoryHistory.h" />
     <ClInclude Include="..\..\xbmc\filesystem\FactoryDirectory.h" />
index b74a896..ed06a3f 100644 (file)
     <ClCompile Include="..\..\xbmc\cores\VideoRenderers\RenderCapture.cpp">
       <Filter>cores\VideoRenderers</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\xbmc\filesystem\CacheCircular.cpp">
+      <Filter>filesystem</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="..\..\xbmc\win32\pch.h">
     <ClInclude Include="..\..\xbmc\utils\GlobalsHandling.h">
       <Filter>utils</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\xbmc\filesystem\CacheCircular.h">
+      <Filter>filesystem</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="..\..\xbmc\win32\XBMC.ico">
diff --git a/xbmc/filesystem/CacheCircular.cpp b/xbmc/filesystem/CacheCircular.cpp
new file mode 100644 (file)
index 0000000..6f656e3
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *      Copyright (C) 2005-2008 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "system.h"
+#include "utils/log.h"
+#include "threads/SingleLock.h"
+#include "utils/TimeUtils.h"
+#include "CacheCircular.h"
+
+using namespace XFILE;
+
+CCacheCircular::CCacheCircular(size_t front, size_t back)
+ : CCacheStrategy()
+ , m_beg(0)
+ , m_end(0)
+ , m_cur(0)
+ , m_buf(NULL)
+ , m_size(front + back)
+ , m_size_back(back)
+{
+}
+
+CCacheCircular::~CCacheCircular()
+{
+  Close();
+}
+
+int CCacheCircular::Open()
+{
+  m_buf = new uint8_t[m_size];
+  m_beg = 0;
+  m_end = 0;
+  m_cur = 0;
+  return CACHE_RC_OK;
+}
+
+int CCacheCircular::Close()
+{
+  delete[] m_buf;
+  m_buf = NULL;
+  return CACHE_RC_OK;
+}
+
+int CCacheCircular::WriteToCache(const char *buf, size_t len)
+{
+  CSingleLock lock(m_sync);
+
+  // where are we in the buffer
+  size_t pos   = m_end % m_size;
+  size_t limit = m_size - m_size_back - (size_t)(m_end - m_cur);
+  size_t wrap  = m_size - pos;
+
+  // limit by max forward size
+  if(len > limit)
+    len = limit;
+
+  // limit to wrap point
+  if(len > wrap)
+    len = wrap;
+
+  // write the data
+  memcpy(m_buf + pos, buf, len);
+  m_end += len;
+
+  // drop history that was overwritten
+  if(m_end - m_beg > m_size)
+    m_beg = m_end - m_size;
+
+  m_written.Set();
+
+  return len;
+}
+
+int CCacheCircular::ReadFromCache(char *buf, size_t len)
+{
+  CSingleLock lock(m_sync);
+
+  size_t pos   = m_cur % m_size;
+  size_t avail = std::min(m_size - pos, (size_t)(m_end - m_cur));
+
+  if(avail == 0)
+  {
+    if(IsEndOfInput())
+      return CACHE_RC_EOF;
+    else
+      return CACHE_RC_WOULD_BLOCK;
+  }
+
+  if(len > avail)
+    len = avail;
+
+  memcpy(buf, m_buf + pos, len);
+  m_cur += len;
+
+  if (len > 0)
+    m_space.Set();
+
+  return len;
+}
+
+int64_t CCacheCircular::WaitForData(unsigned int minumum, unsigned int millis)
+{
+  CSingleLock lock(m_sync);
+  uint64_t avail = m_end - m_cur;
+
+  if(millis == 0 || IsEndOfInput())
+    return avail;
+
+  if(minumum > m_size - m_size_back)
+    minumum = m_size - m_size_back;
+
+  unsigned int time = CTimeUtils::GetTimeMS() + millis;
+  while (!IsEndOfInput() && avail < minumum && CTimeUtils::GetTimeMS() < time )
+  {
+    lock.Leave();
+    m_written.WaitMSec(50); // may miss the deadline. shouldn't be a problem.
+    lock.Enter();
+    avail = m_end - m_cur;
+  }
+
+  return avail;
+}
+
+int64_t CCacheCircular::Seek(int64_t pos, int iWhence)
+{
+  if (iWhence != SEEK_SET)
+    return CACHE_RC_ERROR;
+
+  CSingleLock lock(m_sync);
+
+  // if seek is a bit over what we have, try to wait a few seconds for the data to be available.
+  // we try to avoid a (heavy) seek on the source
+  if ((uint64_t)pos >= m_end && (uint64_t)pos < m_end + 100000)
+  {
+    lock.Leave();
+    WaitForData((size_t)(pos - m_cur), 5000);
+    lock.Enter();
+  }
+
+  if((uint64_t)pos >= m_beg && (uint64_t)pos <= m_end)
+  {
+    m_cur = pos;
+    return pos;
+  }
+
+  return CACHE_RC_ERROR;
+}
+
+void CCacheCircular::Reset(int64_t pos)
+{
+  CSingleLock lock(m_sync);
+  m_end = pos;
+  m_beg = pos;
+  m_cur = pos;
+}
+
diff --git a/xbmc/filesystem/CacheCircular.h b/xbmc/filesystem/CacheCircular.h
new file mode 100644 (file)
index 0000000..c841552
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *      Copyright (C) 2005-2008 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program 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 General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#ifndef CACHECIRCULAR_H
+#define CACHECIRCULAR_H
+
+#include "CacheStrategy.h"
+#include "threads/CriticalSection.h"
+#include "threads/Event.h"
+
+namespace XFILE {
+
+class CCacheCircular : public CCacheStrategy
+{
+public:
+    CCacheCircular(size_t front, size_t back);
+    virtual ~CCacheCircular();
+
+    virtual int Open() ;
+    virtual int Close();
+
+    virtual int WriteToCache(const char *buf, size_t len) ;
+    virtual int ReadFromCache(char *buf, size_t len) ;
+    virtual int64_t WaitForData(unsigned int minimum, unsigned int iMillis) ;
+
+    virtual int64_t Seek(int64_t pos, int iWhence) ;
+    virtual void Reset(int64_t pos) ;
+
+protected:
+    uint64_t          m_beg;
+    uint64_t          m_end;
+    uint64_t          m_cur;
+    uint8_t          *m_buf;
+    size_t            m_size;
+    size_t            m_size_back;
+    CCriticalSection  m_sync;
+    CEvent            m_written;
+};
+
+} // namespace XFILE
+#endif
index fb7cc45..9c36187 100644 (file)
 #include "File.h"
 #include "URL.h"
 
-#include "CacheMemBuffer.h"
+#include "CacheCircular.h"
 #include "threads/SingleLock.h"
 #include "utils/log.h"
+#include "settings/AdvancedSettings.h"
 
 using namespace AUTOPTR;
 using namespace XFILE;
@@ -40,7 +41,7 @@ CFileCache::CFileCache()
    m_nSeekResult = 0;
    m_seekPos = 0;
    m_readPos = 0;
-   m_pCache = new CacheMemBuffer();
+   m_pCache = new CCacheCircular(g_advancedSettings.m_cacheMemBufferSize, g_advancedSettings.m_cacheMemBufferSize);
    m_seekPossible = 0;
 }
 
index 168d14b..12591f9 100644 (file)
@@ -5,6 +5,7 @@ CXXFLAGS+=-D__STDC_FORMAT_MACROS \
 SRCS=AddonsDirectory.cpp \
      ASAPFileDirectory.cpp \
      CacheMemBuffer.cpp \
+     CacheCircular.cpp \
      CacheStrategy.cpp \
      CDDADirectory.cpp \
      DAAPDirectory.cpp \