##// END OF EJS Templates
inotify: server: use dirstate instead of repo
Nicolas Dumazet -
r9350:b789ea38 default
parent child Browse files
Show More
@@ -34,13 +34,11 b' def split(path):'
34
34
35 walk_ignored_errors = (errno.ENOENT, errno.ENAMETOOLONG)
35 walk_ignored_errors = (errno.ENOENT, errno.ENAMETOOLONG)
36
36
37 def walkrepodirs(repo):
37 def walkrepodirs(dirstate, absroot):
38 '''Iterate over all subdirectories of this repo.
38 '''Iterate over all subdirectories of this repo.
39 Exclude the .hg directory, any nested repos, and ignored dirs.'''
39 Exclude the .hg directory, any nested repos, and ignored dirs.'''
40 rootslash = repo.root + os.sep
41
42 def walkit(dirname, top):
40 def walkit(dirname, top):
43 fullpath = rootslash + dirname
41 fullpath = join(absroot, dirname)
44 try:
42 try:
45 for name, kind in osutil.listdir(fullpath):
43 for name, kind in osutil.listdir(fullpath):
46 if kind == stat.S_IFDIR:
44 if kind == stat.S_IFDIR:
@@ -49,7 +47,7 b' def walkrepodirs(repo):'
49 return
47 return
50 else:
48 else:
51 d = join(dirname, name)
49 d = join(dirname, name)
52 if repo.dirstate._ignore(d):
50 if dirstate._ignore(d):
53 continue
51 continue
54 for subdir in walkit(d, False):
52 for subdir in walkit(d, False):
55 yield subdir
53 yield subdir
@@ -60,18 +58,16 b' def walkrepodirs(repo):'
60
58
61 return walkit('', True)
59 return walkit('', True)
62
60
63 def walk(repo, root):
61 def walk(dirstate, absroot, root):
64 '''Like os.walk, but only yields regular files.'''
62 '''Like os.walk, but only yields regular files.'''
65
63
66 # This function is critical to performance during startup.
64 # This function is critical to performance during startup.
67
65
68 rootslash = repo.root + os.sep
69
70 def walkit(root, reporoot):
66 def walkit(root, reporoot):
71 files, dirs = [], []
67 files, dirs = [], []
72
68
73 try:
69 try:
74 fullpath = rootslash + root
70 fullpath = join(absroot, root)
75 for name, kind in osutil.listdir(fullpath):
71 for name, kind in osutil.listdir(fullpath):
76 if kind == stat.S_IFDIR:
72 if kind == stat.S_IFDIR:
77 if name == '.hg':
73 if name == '.hg':
@@ -80,7 +76,7 b' def walk(repo, root):'
80 else:
76 else:
81 dirs.append(name)
77 dirs.append(name)
82 path = join(root, name)
78 path = join(root, name)
83 if repo.dirstate._ignore(path):
79 if dirstate._ignore(path):
84 continue
80 continue
85 for result in walkit(path, False):
81 for result in walkit(path, False):
86 yield result
82 yield result
@@ -98,7 +94,7 b' def walk(repo, root):'
98
94
99 return walkit(root, root == '')
95 return walkit(root, root == '')
100
96
101 def _explain_watch_limit(ui, repo):
97 def _explain_watch_limit(ui, dirstate, rootabs):
102 path = '/proc/sys/fs/inotify/max_user_watches'
98 path = '/proc/sys/fs/inotify/max_user_watches'
103 try:
99 try:
104 limit = int(file(path).read())
100 limit = int(file(path).read())
@@ -112,7 +108,7 b' def _explain_watch_limit(ui, repo):'
112 ui.warn(_('*** this limit is too low to watch every '
108 ui.warn(_('*** this limit is too low to watch every '
113 'directory in this repository\n'))
109 'directory in this repository\n'))
114 ui.warn(_('*** counting directories: '))
110 ui.warn(_('*** counting directories: '))
115 ndirs = len(list(walkrepodirs(repo)))
111 ndirs = len(list(walkrepodirs(dirstate, rootabs)))
116 ui.warn(_('found %d\n') % ndirs)
112 ui.warn(_('found %d\n') % ndirs)
117 newlimit = min(limit, 1024)
113 newlimit = min(limit, 1024)
118 while newlimit < ((limit + ndirs) * 1.1):
114 while newlimit < ((limit + ndirs) * 1.1):
@@ -121,7 +117,7 b' def _explain_watch_limit(ui, repo):'
121 (limit, newlimit))
117 (limit, newlimit))
122 ui.warn(_('*** echo %d > %s\n') % (newlimit, path))
118 ui.warn(_('*** echo %d > %s\n') % (newlimit, path))
123 raise util.Abort(_('cannot watch %s until inotify watch limit is raised')
119 raise util.Abort(_('cannot watch %s until inotify watch limit is raised')
124 % repo.root)
120 % rootabs)
125
121
126 class pollable(object):
122 class pollable(object):
127 """
123 """
@@ -309,10 +305,11 b' class repowatcher(pollable):'
309 inotify.IN_UNMOUNT |
305 inotify.IN_UNMOUNT |
310 0)
306 0)
311
307
312 def __init__(self, ui, repo):
308 def __init__(self, ui, dirstate, root):
313 self.ui = ui
309 self.ui = ui
314 self.repo = repo
310 self.dirstate = dirstate
315 self.wprefix = join(repo.root, '')
311
312 self.wprefix = join(root, '')
316 self.prefixlen = len(self.wprefix)
313 self.prefixlen = len(self.wprefix)
317 try:
314 try:
318 self.watcher = watcher.watcher()
315 self.watcher = watcher.watcher()
@@ -352,7 +349,7 b' class repowatcher(pollable):'
352
349
353 def dirstate_info(self):
350 def dirstate_info(self):
354 try:
351 try:
355 st = os.lstat(self.repo.join('dirstate'))
352 st = os.lstat(self.wprefix + '.hg/dirstate')
356 return st.st_mtime, st.st_ino
353 return st.st_mtime, st.st_ino
357 except OSError, err:
354 except OSError, err:
358 if err.errno != errno.ENOENT:
355 if err.errno != errno.ENOENT:
@@ -372,16 +369,16 b' class repowatcher(pollable):'
372 return
369 return
373 if err.errno != errno.ENOSPC:
370 if err.errno != errno.ENOSPC:
374 raise
371 raise
375 _explain_watch_limit(self.ui, self.repo)
372 _explain_watch_limit(self.ui, self.dirstate, self.wprefix)
376
373
377 def setup(self):
374 def setup(self):
378 self.ui.note(_('watching directories under %r\n') % self.wprefix)
375 self.ui.note(_('watching directories under %r\n') % self.wprefix)
379 self.add_watch(self.repo.path, inotify.IN_DELETE)
376 self.add_watch(self.wprefix + '.hg', inotify.IN_DELETE)
380 self.check_dirstate()
377 self.check_dirstate()
381
378
382 def filestatus(self, fn, st):
379 def filestatus(self, fn, st):
383 try:
380 try:
384 type_, mode, size, time = self.repo.dirstate._map[fn][:4]
381 type_, mode, size, time = self.dirstate._map[fn][:4]
385 except KeyError:
382 except KeyError:
386 type_ = '?'
383 type_ = '?'
387 if type_ == 'n':
384 if type_ == 'n':
@@ -393,7 +390,7 b' class repowatcher(pollable):'
393 if time != int(st_mtime):
390 if time != int(st_mtime):
394 return 'l'
391 return 'l'
395 return 'n'
392 return 'n'
396 if type_ == '?' and self.repo.dirstate._ignore(fn):
393 if type_ == '?' and self.dirstate._ignore(fn):
397 return 'i'
394 return 'i'
398 return type_
395 return type_
399
396
@@ -458,7 +455,7 b' class repowatcher(pollable):'
458 # may have vanished from the dirstate; we must clean them up.
455 # may have vanished from the dirstate; we must clean them up.
459 nuke = []
456 nuke = []
460 for wfn, ignore in self.statustrees[key].walk(key):
457 for wfn, ignore in self.statustrees[key].walk(key):
461 if wfn not in self.repo.dirstate:
458 if wfn not in self.dirstate:
462 nuke.append(wfn)
459 nuke.append(wfn)
463 for wfn in nuke:
460 for wfn in nuke:
464 root, fn = split(wfn)
461 root, fn = split(wfn)
@@ -466,9 +463,9 b' class repowatcher(pollable):'
466 del self.tree.dir(root).files[fn]
463 del self.tree.dir(root).files[fn]
467
464
468 def scan(self, topdir=''):
465 def scan(self, topdir=''):
469 ds = self.repo.dirstate._map.copy()
466 ds = self.dirstate._map.copy()
470 self.add_watch(join(self.wprefix, topdir), self.mask)
467 self.add_watch(join(self.wprefix, topdir), self.mask)
471 for root, dirs, files in walk(self.repo, topdir):
468 for root, dirs, files in walk(self.dirstate, self.wprefix, topdir):
472 for d in dirs:
469 for d in dirs:
473 self.add_watch(join(root, d), self.mask)
470 self.add_watch(join(root, d), self.mask)
474 wroot = root[self.prefixlen:]
471 wroot = root[self.prefixlen:]
@@ -500,7 +497,7 b' class repowatcher(pollable):'
500 if not self.ui.debugflag:
497 if not self.ui.debugflag:
501 self.last_event = None
498 self.last_event = None
502 self.ui.note(_('%s dirstate reload\n') % self.event_time())
499 self.ui.note(_('%s dirstate reload\n') % self.event_time())
503 self.repo.dirstate.invalidate()
500 self.dirstate.invalidate()
504 self.handle_timeout()
501 self.handle_timeout()
505 self.scan()
502 self.scan()
506 self.ui.note(_('%s end dirstate reload\n') % self.event_time())
503 self.ui.note(_('%s end dirstate reload\n') % self.event_time())
@@ -516,8 +513,8 b' class repowatcher(pollable):'
516 # But it's easier to do nothing than to open that can of
513 # But it's easier to do nothing than to open that can of
517 # worms.
514 # worms.
518
515
519 if '_ignore' in self.repo.dirstate.__dict__:
516 if '_ignore' in self.dirstate.__dict__:
520 delattr(self.repo.dirstate, '_ignore')
517 delattr(self.dirstate, '_ignore')
521 self.ui.note(_('rescanning due to .hgignore change\n'))
518 self.ui.note(_('rescanning due to .hgignore change\n'))
522 self.handle_timeout()
519 self.handle_timeout()
523 self.scan()
520 self.scan()
@@ -560,7 +557,7 b' class repowatcher(pollable):'
560 try:
557 try:
561 st = self.stat(wpath)
558 st = self.stat(wpath)
562 if stat.S_ISREG(st[0]):
559 if stat.S_ISREG(st[0]):
563 if self.repo.dirstate[wpath] in 'lmn':
560 if self.dirstate[wpath] in 'lmn':
564 self.updatefile(wpath, st)
561 self.updatefile(wpath, st)
565 except OSError:
562 except OSError:
566 pass
563 pass
@@ -574,7 +571,7 b' class repowatcher(pollable):'
574 self.check_dirstate()
571 self.check_dirstate()
575 return
572 return
576
573
577 self.deletefile(wpath, self.repo.dirstate[wpath])
574 self.deletefile(wpath, self.dirstate[wpath])
578
575
579 def process_create(self, wpath, evt):
576 def process_create(self, wpath, evt):
580 if self.ui.debugflag:
577 if self.ui.debugflag:
@@ -678,12 +675,11 b' class server(pollable):'
678 """
675 """
679 Listens for client queries on unix socket inotify.sock
676 Listens for client queries on unix socket inotify.sock
680 """
677 """
681 def __init__(self, ui, repo, repowatcher, timeout):
678 def __init__(self, ui, root, repowatcher, timeout):
682 self.ui = ui
679 self.ui = ui
683 self.repo = repo
684 self.repowatcher = repowatcher
680 self.repowatcher = repowatcher
685 self.sock = socket.socket(socket.AF_UNIX)
681 self.sock = socket.socket(socket.AF_UNIX)
686 self.sockpath = self.repo.join('inotify.sock')
682 self.sockpath = join(root, '.hg/inotify.sock')
687 self.realsockpath = None
683 self.realsockpath = None
688 try:
684 try:
689 self.sock.bind(self.sockpath)
685 self.sock.bind(self.sockpath)
@@ -813,9 +809,8 b' class server(pollable):'
813 class master(object):
809 class master(object):
814 def __init__(self, ui, repo, timeout=None):
810 def __init__(self, ui, repo, timeout=None):
815 self.ui = ui
811 self.ui = ui
816 self.repo = repo
812 self.repowatcher = repowatcher(ui, repo.dirstate, repo.root)
817 self.repowatcher = repowatcher(ui, repo)
813 self.server = server(ui, repo.root, self.repowatcher, timeout)
818 self.server = server(ui, repo, self.repowatcher, timeout)
819
814
820 def shutdown(self):
815 def shutdown(self):
821 for obj in pollable.instances.itervalues():
816 for obj in pollable.instances.itervalues():
General Comments 0
You need to be logged in to leave comments. Login now