Re: vdr-checkts + vdrnfofs

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

> I tried to set up a dlna server with an earlier version of vdr-nfofs a few
> months ago. It kinda worked but there were some performance problems in
> regard to file system operations. I hacked a file descriptor cache into the
> python code which helped a bit. Tobi might have included this in the new
> version.

Looks like my patches haven't been accepted for 0.7. You can try my patchset but I haven't worked on that for some months now. Patch is not minimal and not cleanly separated, so you should pick the tidbits you like.

Cya, Ed
diff -ur vdrnfofs-0.6/vdrnfofs/concatenated_file_reader.py vdrnfofs-0.6.tyger1//vdrnfofs/concatenated_file_reader.py
--- vdrnfofs-0.6/vdrnfofs/concatenated_file_reader.py	2011-04-14 23:59:21.000000000 +0200
+++ vdrnfofs-0.6.tyger1//vdrnfofs/concatenated_file_reader.py	2011-04-18 22:35:43.776907385 +0200
@@ -20,32 +20,37 @@
 # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
 import os
+from threading import Lock
+from cStringIO import StringIO
 
 class ConcatenatedFileReader:
     def __init__(self, filenames):
         self.files = [(f, os.path.getsize(f)) for f in filenames]
         self.current_filename = None
         self.current_file = None
+        self.rwlock = Lock()
 
     def read(self, offset, size):
-        buffer = ""
+        buffer = StringIO()
         ptr = offset
-        while (len(buffer) < size):
-            (filename, file_offset) = self.filename_from_offset(ptr)
-            if filename:
-                if (self.current_filename != filename):
-                    if self.current_file:
-                        self.current_file.close()
-                    self.current_filename = filename
-                    self.current_file = open(filename, 'r')
-                self.current_file.seek(file_offset)
-                buffer += self.current_file.read(size - len(buffer))
-                ptr = offset + len(buffer)
-            else:
-                break
-        return buffer
+        with self.rwlock:
+            while (buffer.tell() < size):
+                (filename, file_offset) = self.filename_from_offset(ptr)
+                if filename:
+                    if (self.current_filename != filename):
+                        if self.current_file:
+                            self.current_file.close()
+                        self.current_filename = filename
+                        self.current_file = open(filename, 'r')
+                    self.current_file.seek(file_offset)
+                    buffer.write(self.current_file.read(size - buffer.tell()))
+                    ptr = offset + buffer.tell()
+                else:
+                    break
+        return buffer.getvalue()
 
-    def release(self):
+    def __del__(self):
+        # print "CFR::DEL"
         if self.current_file:
             self.current_file.close()
 
Only in vdrnfofs-0.6.tyger1//vdrnfofs: concatenated_file_reader.py~
diff -ur vdrnfofs-0.6/vdrnfofs/filesystemnodes.py vdrnfofs-0.6.tyger1//vdrnfofs/filesystemnodes.py
--- vdrnfofs-0.6/vdrnfofs/filesystemnodes.py	2011-04-14 23:27:02.000000000 +0200
+++ vdrnfofs-0.6.tyger1//vdrnfofs/filesystemnodes.py	2011-04-18 22:39:19.540905997 +0200
@@ -26,6 +26,7 @@
 
 from concatenated_file_reader import *
 from vdr import *
+from threading import Lock
 
 class NodeAttributes(fuse.Stat):
     def __init__(self):
@@ -40,40 +41,90 @@
         self.st_mtime = 0
         self.st_ctime = 0
 
+
 class MpgNode:
+    cachesize = 20
+    cachelock = Lock()
+    cache = []
+
+    @classmethod
+    def create(cls, path, cache):
+        if not cache:
+            return cls(path)
+        with cls.cachelock:
+            index = next((i for i in xrange(len(cls.cache)-1, -1, -1) if cls.cache[i].key == path), None)
+            if index is not None:
+                # print "%s HIT" % cls.__name__
+                node = cls.cache.pop(index)
+            else:
+                # print "%s MISS" % cls.__name__
+                node = cls(path)
+                if len(cls.cache) > cls.cachesize:
+                    del cls.cache[0]
+            cls.cache.append(node)
+            # print "%s cache size: %d" %(cls.__name__, len(cls.cache))
+            return node
+
     def __init__(self, path):
+        # print "MpgNode::init %s" % path
+        self.key = path
         self.path = os.path.normpath(path)
         self.mpeg_files = glob.glob(path + '/[0-9]*.vdr')
         if not self.mpeg_files:
             self.mpeg_files = glob.glob(path + '/[0-9]*.ts')
         self.mpeg_files.sort()
-        self.file_system_name = os.path.basename(os.path.abspath(path + '/..')) + '_' + os.path.basename(path) + '.mpg'
+        self.file_system_name ="%s_%s.mpg" % (os.path.basename(os.path.abspath(path + '/..')), os.path.basename(path)) 
         self.reader = ConcatenatedFileReader(self.mpeg_files)
-
-    def size(self):
         size = 0
         for file in self.mpeg_files:
             size += os.path.getsize(file)
-        return size
+        self.filesize = size
 
-    def read(self, offset, size):
-         return self.reader.read(offset, size)
+    def size(self):
+        # print "MpgNode::size"
+        return self.filesize
 
-    def release(self):
-         return self.reader.release()
+    def read(self, offset, size):
+        # print "MpgNode::read %d" % offset
+        return self.reader.read(offset, size)
 
     def get_stat(self):
+        # print "MpgNode::get_stat"
         attr = NodeAttributes()
-        attr.st_mode = stat.S_IFREG | 644
+        attr.st_mode = stat.S_IFREG | 0444
         attr.st_nlink = 1
-        attr.st_size = self.size()
+        attr.st_size = self.filesize
         return attr
 
 
 class NfoNode:
+    cachesize = 20
+    cachelock = Lock()
+    cache = []
+
+    @classmethod
+    def create(cls, path, cache):
+        if not cache:
+            return cls(path)
+        with cls.cachelock:
+            index = next((i for i in xrange(len(cls.cache)-1, -1, -1) if cls.cache[i].key == path), None)
+            if index is not None:
+                # print "%s HIT" % cls.__name__
+                node = cls.cache.pop(index)
+            else:
+                # print "%s MISS" % cls.__name__
+                node = cls(path)
+                if len(cls.cache) > cls.cachesize:
+                    del cls.cache[0]
+            cls.cache.append(node)
+            # print "%s cache size: %d" %(cls.__name__, len(cls.cache))
+            return node
+
     def __init__(self, path):
+        # print "NfoNode::init %s" % path
+        self.key = path
         self.path = os.path.normpath(path)
-        self.file_system_name = os.path.basename(os.path.abspath(path + '/..')) + '_' + os.path.basename(path) + '.nfo'
+        self.file_system_name ="%s_%s.nfo" % (os.path.basename(os.path.abspath(path + '/..')), os.path.basename(path)) 
         if os.path.exists(path + '/info.vdr'):
             info_vdr = InfoVdr(path + '/info.vdr')
         elif os.path.exists(path + '/info'):
@@ -86,39 +137,75 @@
   <plot>%s</plot>
 </movie>
 """ % (info_vdr['T'], info_vdr['D'])
+        self.contentsize = len(self.nfo_content)
 
     def size(self):
-        return len(self.nfo_content)
+        return self.contentsize
 
     def read(self, offset, size):
+       # print "NfoNode::read %s" % offset
        return self.nfo_content[offset:offset+size]
 
     def get_stat(self):
+        # print "NfoNode::get_stat"
         attr = NodeAttributes()
-        attr.st_mode = stat.S_IFREG | 644
+        attr.st_mode = stat.S_IFREG | 0444
         attr.st_nlink = 1
-        attr.st_size = self.size()
+        attr.st_size = self.contentsize
         return attr
 
 
 class DirNode:
+    cachesize = 100
+    cachelock = Lock()
+    cache = []
+
+    @classmethod
+    def create(cls, path, cache):
+        if not cache:
+            return cls(path)
+        with cls.cachelock:
+            index = next((i for i in xrange(len(cls.cache)-1, -1, -1) if cls.cache[i].key == path), None)
+            if index is not None:
+                # print "%s HIT" % cls.__name__
+                node = cls.cache.pop(index)
+            else:
+                # print "%s MISS" % cls.__name__
+                node = cls(path)
+                if len(cls.cache) > cls.cachesize:
+                    del cls.cache[0]
+            cls.cache.append(node)
+            # print "%s cache size: %d" %(cls.__name__, len(cls.cache))
+            return node
+
     def __init__(self, path):
+        # print "DirNode::init %s" % path
+        self.key = path
         self.path = os.path.normpath(path)
         self.file_system_name = os.path.basename(path)
         self.cache = []
+        self.mysize = None
 
     def content(self):
+        # print "DirNode::content %s" % self.path
         if not self.cache:
+            # print "without cache"
             for entry in os.listdir(self.path):
-                entry = self.path + '/' + entry
+                entry = "/".join((self.path, entry))
                 if self.is_sub_folder(entry):
-                    self.cache.append(DirNode(entry))
+                    self.cache.append(DirNode.create(entry, True))
                 for recording in glob.glob(entry + '/*.rec'):
                     if os.path.exists(recording + '/info.vdr') or os.path.exists(recording + '/info'):
-                        self.cache.append(MpgNode(recording))
-                        self.cache.append(NfoNode(recording))
+                        self.cache.append(MpgNode(recording)) # DONT CACHE!
+                        self.cache.append(NfoNode(recording)) # DONT CACHE!
         return self.cache
 
+    def size(self):
+        # print "DirNode::size"
+        if not self.mysize:
+            self.mysize = len(self.content())
+        return self.mysize
+
     def is_sub_folder(self, dir):
         if not os.path.isdir(dir):
             return False
@@ -130,7 +217,8 @@
         return False
 
     def get_stat(self):
+        # print "DirNode::get_stat"
         attr = NodeAttributes()
-        attr.st_mode = stat.S_IFDIR | 0755
-        attr.st_nlink = 2 + len(self.content())
+        attr.st_mode = stat.S_IFDIR | 0555
+        attr.st_nlink = 2 + self.size()
         return attr
Only in vdrnfofs-0.6.tyger1//vdrnfofs: filesystemnodes.py~
diff -ur vdrnfofs-0.6/vdrnfofs/vdrnfofs.py vdrnfofs-0.6.tyger1//vdrnfofs/vdrnfofs.py
--- vdrnfofs-0.6/vdrnfofs/vdrnfofs.py	2011-04-14 23:35:57.000000000 +0200
+++ vdrnfofs-0.6.tyger1//vdrnfofs/vdrnfofs.py	2011-04-18 22:38:40.540905398 +0200
@@ -29,30 +29,32 @@
 from concatenated_file_reader import *
 from vdr import *
 from filesystemnodes import *
+from traceback import format_exc
 
 fuse.fuse_python_api = (0, 2)
 
-def get_node(video, path):
+def get_node(video, path, cache=False):
     virtual_path, virtual_file_extension = os.path.splitext(path)
     if virtual_file_extension in ['.mpg', '.nfo']:
         p = virtual_path.rfind('_')
         if p > 0:
-            video_path = video + '/' + virtual_path[0:p] + '/' + virtual_path[p+1:]
+            video_path = "%s/%s/%s" % (video, virtual_path[0:p], virtual_path[p+1:])
             if not os.path.isdir(video_path):
                return None
             elif virtual_file_extension == '.mpg':
-                return MpgNode(video_path)
+                return MpgNode.create(video_path, cache)
             elif virtual_file_extension == '.nfo':
-                return NfoNode(video_path)
+                return NfoNode.create(video_path, cache)
     else:
-        if os.path.isdir(video + '/' + path):
-            return DirNode(video + path)
+        dir_path = video + path
+        if os.path.isdir(dir_path):
+            return DirNode.create(dir_path, cache)
     return None
 
 class VdrNfoFsFile:
     def __init__(self, path, flags, *mode):
         self.path = path
-        self.node = get_node(VdrNfoFsFile.video_root, path)
+        self.node = get_node(VdrNfoFsFile.video_root, path, True)
 
     def read(self, size, offset):
         try:
@@ -60,10 +62,10 @@
                 return -errno.ENOENT
             return self.node.read(offset, size)
         except:
-            syslog.syslog('VdrFuseFs: Unexpected error for read(%s)' % self.path)
+            syslog.syslog('VdrFuseFs: Unexpected error for read(%s): ' % (self.path, format_exc()))
 
-    def release(self, flags):
-        self.node.release()
+#    def release(self, flags):
+        # print "VdrNfoFsFile::release %s" % self.node.key
 
 #    def write(self, buf, offset):
 #        return 0
@@ -90,24 +92,26 @@
         self.video = ""
 
     def getattr(self, path):
+        # print "VNF::getattr"
         try:
-            node = get_node(self.video, path)
+            node = get_node(self.video, path, False)
             if node:
+                # print "got node %s" % node.key
                 return node.get_stat()
             return -errno.ENOENT
         except:
-            syslog.syslog('VdrFuseFs: Unexpected error for getattr(%s): %s' % path)
+            syslog.syslog('VdrFuseFs: Unexpected error for getattr(%s): %s' % (path, format_exc()))
 
     def readdir(self, path, offset):
         try:
             yield fuse.Direntry('.')
             yield fuse.Direntry('..')
-            node = get_node(self.video, path)
+            node = get_node(self.video, path, True)
             if node:
                 for item in node.content():
                     yield fuse.Direntry(item.file_system_name)
         except:
-            syslog.syslog('VdrFuseFs: Unexpected error for readdir(%s)' % path)
+            syslog.syslog('VdrFuseFs: Unexpected error for readdir(%s): %s' % (path, format_exc()))
 
     def main(self, *a, **kw):
         VdrNfoFsFile.video_root = self.video
Only in vdrnfofs-0.6.tyger1//vdrnfofs: vdrnfofs.py~
diff -ur vdrnfofs-0.6/vdrnfofs/vdr.py vdrnfofs-0.6.tyger1//vdrnfofs/vdr.py
--- vdrnfofs-0.6/vdrnfofs/vdr.py	2011-04-14 23:27:14.000000000 +0200
+++ vdrnfofs-0.6.tyger1//vdrnfofs/vdr.py	2011-04-18 16:50:09.040905717 +0200
@@ -23,10 +23,10 @@
     def __init__(self, filename = None):
         self.values = {'T' : 'Unknown', 'D': 'No Description'}
         if filename:
-            file = open(filename, 'r')
-            for line in file:
-                line = line.rstrip("\r\n")
-                self.values[line[0]] = line[2:]
+            with open(filename, 'r') as file:
+                for line in file:
+                    line = line.rstrip("\r\n")
+                    self.values[line[0]] = line[2:]
 
     def __getitem__(self, key):
         return self.values[key] if self.values.has_key(key) else ''
Only in vdrnfofs-0.6.tyger1//vdrnfofs: vdr.py~
_______________________________________________
vdr mailing list
vdr@xxxxxxxxxxx
http://www.linuxtv.org/cgi-bin/mailman/listinfo/vdr

[Index of Archives]     [Linux Media]     [Asterisk]     [DCCP]     [Netdev]     [Xorg]     [Util Linux NG]     [Xfree86]     [Big List of Linux Books]     [Fedora Users]     [Fedora Women]     [ALSA Devel]     [Linux USB]

  Powered by Linux