Commits

Nicolas Dumazet  committed f7ff458

improve matching

  • Participants
  • Parent commits 8807418

Comments (0)

Files changed (3)

+# HG changeset patch
+# User Nicolas Dumazet <nicdumz.commits@gmail.com>
+# Date 1259313050 -32400
+inotify: avoid repetitive computations before lookup
+
+For each matched name, do these operations once instead of 6-8 times:
+* normalize name
+* name.split('/')
+
+diff --git a/hgext/inotify/server.py b/hgext/inotify/server.py
+--- a/hgext/inotify/server.py
++++ b/hgext/inotify/server.py
+@@ -124,25 +124,21 @@
+             for e in dir.walk(states):
+                 yield e
+ 
+-    def lookup(self, states, path, visited=None):
++    def lookup(self, states, paths, visited=None):
+         """
++        paths is a path.split('/')
+         yield root-relative filenames that match path, and whose
+         status are in states:
+         * if path is a file, yield path
+         * if path is a directory, yield directory files
+         * if path is not tracked, yield nothing
+         """
+-        if path[-1] == '/':
+-            path = path[:-1]
+-
+-        paths = path.split('/')
+-
+         # we need to check separately for last node
+-        last = paths.pop()
++        last = paths[-1]
+ 
+         tree = self
+         try:
+-            for dir in paths:
++            for dir in paths[:-1]:
+                 tree = tree.dirs[dir]
+         except KeyError:
+             # path is not tracked
+@@ -164,7 +160,7 @@
+                     # path is a file
+                     if visited is not None:
+                         visited.add(tree.path)
+-                    yield path
++                    yield join(tree.path, last)
+             except KeyError:
+                 # path is not tracked
+                 pass
+@@ -380,13 +376,19 @@
+                 for fn, state in tree.walk(states):
+                     yield fn
+         else:
++            split_paths = []
+             # fake a lookup to fill visited, even for empty directories
+-            for fn in names:
+-                list(self.repowatcher.tree.lookup('', fn, visited))
++            for path in names:
++                if path[-1] == '/':
++                    path = path[:-1]
++                paths = path.split('/')
++                split_paths.append(paths)
++
++                list(self.repowatcher.tree.lookup('', paths, visited))
+ 
+             def genresult(states, tree):
+-                for fn in names:
+-                    for f in tree.lookup(states, fn):
++                for sp in split_paths:
++                    for f in tree.lookup(states, sp):
+                         yield f
+ 
+         return ['\0'.join(r) for r in [

File no-match-under

+# HG changeset patch
+# User Nicolas Dumazet <nicdumz.commits@gmail.com>
+# Date 1259313042 -32400
+inotify: improve visited directory emulation
+
+* make sure that "no match under directory" gets raised
+* no need to pass several times the visited dict. Once in the global dict
+  should be enough
+
+diff --git a/hgext/inotify/linuxserver.py b/hgext/inotify/linuxserver.py
+--- a/hgext/inotify/linuxserver.py
++++ b/hgext/inotify/linuxserver.py
+@@ -285,6 +285,7 @@
+ 
+         if evt.mask & inotify.IN_ISDIR:
+             self.scan(wpath)
++            d = self.tree.dir(wpath)
+         else:
+             self.created(wpath)
+ 
+diff --git a/hgext/inotify/server.py b/hgext/inotify/server.py
+--- a/hgext/inotify/server.py
++++ b/hgext/inotify/server.py
+@@ -111,7 +111,7 @@
+                 ret = d
+         return ret
+ 
+-    def walk(self, states, visited=None):
++    def walk(self, states):
+         """
+         yield (filename, status) pairs for items in the trees
+         that have status in states.
+@@ -121,12 +121,10 @@
+             if st in states:
+                 yield join(self.path, file), st
+         for dir in self.dirs.itervalues():
+-            if visited is not None:
+-                visited.add(dir.path)
+             for e in dir.walk(states):
+                 yield e
+ 
+-    def lookup(self, states, path, visited):
++    def lookup(self, states, path, visited=None):
+         """
+         yield root-relative filenames that match path, and whose
+         status are in states:
+@@ -148,20 +146,24 @@
+                 tree = tree.dirs[dir]
+         except KeyError:
+             # path is not tracked
+-            visited.add(tree.path)
++            if visited is not None:
++                visited.add(tree.path)
+             return
+ 
+         try:
+             # if path is a directory, walk it
+             target = tree.dirs[last]
+-            visited.add(target.path)
+-            for file, st in target.walk(states, visited):
+-                yield file
++            if visited is None:
++                for file, st in target.walk(states):
++                    yield file
++            else:
++                visited.add(target.path)
+         except KeyError:
+             try:
+                 if tree.files[last] in states:
+                     # path is a file
+-                    visited.add(tree.path)
++                    if visited is not None:
++                        visited.add(tree.path)
+                     yield path
+             except KeyError:
+                 # path is not tracked
+@@ -378,9 +380,13 @@
+                 for fn, state in tree.walk(states):
+                     yield fn
+         else:
++            # fake a lookup to fill visited, even for empty directories
++            for fn in names:
++                list(self.repowatcher.tree.lookup('', fn, visited))
++
+             def genresult(states, tree):
+                 for fn in names:
+-                    for f in tree.lookup(states, fn, visited):
++                    for f in tree.lookup(states, fn):
+                         yield f
+ 
+         return ['\0'.join(r) for r in [
+diff --git a/tests/test-inotify b/tests/test-inotify
+--- a/tests/test-inotify
++++ b/tests/test-inotify
+@@ -95,6 +95,16 @@
+ hg ci -m 'working'
+ 
+ echo b >> 1844/foo
++mkdir 1844/sub
++echo foo >> 1844/sub/foo
+ hg ci 1844 -m 'broken'
+ 
++# check that "no match under directory" still happens.
++mkdir dummy
++mkdir empty
++cd empty
++hg ci -m"no match" .
++hg ci -m"no match" ../dummy
++cd ..
++
+ kill `cat hg.pid`
+diff --git a/tests/test-inotify.out b/tests/test-inotify.out
+--- a/tests/test-inotify.out
++++ b/tests/test-inotify.out
+@@ -50,3 +50,5 @@
+ 3 files updated, 1 files merged, 0 files removed, 0 files unresolved
+ M a
+ adding 1844/foo
++abort: empty: no match under directory!
++abort: dummy: no match under directory!
 symlink-basic
 dirstate-stat
 inotify-test-permissions
+no-match-under
+matching
 inotify-moverepo
 inotify-wronglstat
 pyfs