Mercurial > hg
comparison hgext/inotify/server.py @ 8605:ed2d9bdbfad2
inotify: do not defer inotify events processing
Doing a part of the event processing and deferring the rest is a bad
habit: it complexifies the code, and it does not respect event ordering!
Moreover, there is already a timeout handling, so that inotify events are
only processed when a treshold is exceeded: there is no requirement to
delay anymore the events processing.
author | Nicolas Dumazet <nicdumz.commits@gmail.com> |
---|---|
date | Fri, 22 May 2009 09:57:53 +0900 |
parents | 578f2a0049cd |
children | 1c5752dabf76 |
comparison
equal
deleted
inserted
replaced
8604:578f2a0049cd | 8605:ed2d9bdbfad2 |
---|---|
149 self.statustrees = dict([(s, {}) for s in self.statuskeys]) | 149 self.statustrees = dict([(s, {}) for s in self.statuskeys]) |
150 | 150 |
151 self.watches = 0 | 151 self.watches = 0 |
152 self.last_event = None | 152 self.last_event = None |
153 | 153 |
154 self.eventq = {} | 154 self.lastevent = {} |
155 self.deferred = 0 | |
156 | 155 |
157 self.ds_info = self.dirstate_info() | 156 self.ds_info = self.dirstate_info() |
158 self.handle_timeout() | 157 self.handle_timeout() |
159 self.scan() | 158 self.scan() |
160 | 159 |
445 self.check_dirstate() | 444 self.check_dirstate() |
446 return | 445 return |
447 | 446 |
448 self.deletefile(wpath, self.repo.dirstate[wpath]) | 447 self.deletefile(wpath, self.repo.dirstate[wpath]) |
449 | 448 |
450 def schedule_work(self, wpath, evt): | 449 def work(self, wpath, evt): |
451 prev = self.eventq.setdefault(wpath, []) | 450 try: |
452 try: | 451 if evt == 'c': |
453 if prev and evt == 'm' and prev[-1] in 'cm': | 452 self.created(wpath) |
454 return | 453 elif evt == 'm': |
455 self.eventq[wpath].append(evt) | 454 if wpath in self.lastevent and self.lastevent[wpath] in 'cm': |
455 return | |
456 self.modified(wpath) | |
457 elif evt == 'd': | |
458 self.deleted(wpath) | |
459 | |
460 self.lastevent[wpath] = evt | |
456 finally: | 461 finally: |
457 self.deferred += 1 | |
458 self.timeout = 250 | 462 self.timeout = 250 |
459 | |
460 def deferred_event(self, wpath, evt): | |
461 if evt == 'c': | |
462 self.created(wpath) | |
463 elif evt == 'm': | |
464 self.modified(wpath) | |
465 elif evt == 'd': | |
466 self.deleted(wpath) | |
467 | 463 |
468 def process_create(self, wpath, evt): | 464 def process_create(self, wpath, evt): |
469 if self.ui.debugflag: | 465 if self.ui.debugflag: |
470 self.ui.note(_('%s event: created %s\n') % | 466 self.ui.note(_('%s event: created %s\n') % |
471 (self.event_time(), wpath)) | 467 (self.event_time(), wpath)) |
472 | 468 |
473 if evt.mask & inotify.IN_ISDIR: | 469 if evt.mask & inotify.IN_ISDIR: |
474 self.scan(wpath) | 470 self.scan(wpath) |
475 else: | 471 else: |
476 self.schedule_work(wpath, 'c') | 472 self.work(wpath, 'c') |
477 | 473 |
478 def process_delete(self, wpath, evt): | 474 def process_delete(self, wpath, evt): |
479 if self.ui.debugflag: | 475 if self.ui.debugflag: |
480 self.ui.note(_('%s event: deleted %s\n') % | 476 self.ui.note(_('%s event: deleted %s\n') % |
481 (self.event_time(), wpath)) | 477 (self.event_time(), wpath)) |
484 tree = self.dir(self.tree, wpath).copy() | 480 tree = self.dir(self.tree, wpath).copy() |
485 for wfn, ignore in self.walk('?', tree): | 481 for wfn, ignore in self.walk('?', tree): |
486 self.deletefile(join(wpath, wfn), '?') | 482 self.deletefile(join(wpath, wfn), '?') |
487 self.scan(wpath) | 483 self.scan(wpath) |
488 else: | 484 else: |
489 self.schedule_work(wpath, 'd') | 485 self.work(wpath, 'd') |
490 | 486 |
491 def process_modify(self, wpath, evt): | 487 def process_modify(self, wpath, evt): |
492 if self.ui.debugflag: | 488 if self.ui.debugflag: |
493 self.ui.note(_('%s event: modified %s\n') % | 489 self.ui.note(_('%s event: modified %s\n') % |
494 (self.event_time(), wpath)) | 490 (self.event_time(), wpath)) |
495 | 491 |
496 if not (evt.mask & inotify.IN_ISDIR): | 492 if not (evt.mask & inotify.IN_ISDIR): |
497 self.schedule_work(wpath, 'm') | 493 self.work(wpath, 'm') |
498 | 494 |
499 def process_unmount(self, evt): | 495 def process_unmount(self, evt): |
500 self.ui.warn(_('filesystem containing %s was unmounted\n') % | 496 self.ui.warn(_('filesystem containing %s was unmounted\n') % |
501 evt.fullpath) | 497 evt.fullpath) |
502 sys.exit(0) | 498 sys.exit(0) |
531 inotify.IN_MOVED_FROM): | 527 inotify.IN_MOVED_FROM): |
532 self.process_delete(wpath, evt) | 528 self.process_delete(wpath, evt) |
533 elif evt.mask & (inotify.IN_CREATE | inotify.IN_MOVED_TO): | 529 elif evt.mask & (inotify.IN_CREATE | inotify.IN_MOVED_TO): |
534 self.process_create(wpath, evt) | 530 self.process_create(wpath, evt) |
535 | 531 |
532 self.lastevent.clear() | |
533 | |
536 def handle_timeout(self): | 534 def handle_timeout(self): |
537 if not self.registered: | 535 if not self.registered: |
538 if self.ui.debugflag: | 536 if self.ui.debugflag: |
539 self.ui.note(_('%s hooking back up with %d bytes readable\n') % | 537 self.ui.note(_('%s hooking back up with %d bytes readable\n') % |
540 (self.event_time(), self.threshold.readable())) | 538 (self.event_time(), self.threshold.readable())) |
541 self.read_events(0) | 539 self.read_events(0) |
542 self.master.poll.register(self, select.POLLIN) | 540 self.master.poll.register(self, select.POLLIN) |
543 self.registered = True | 541 self.registered = True |
544 | 542 |
545 if self.eventq: | |
546 if self.ui.debugflag: | |
547 self.ui.note(_('%s processing %d deferred events as %d\n') % | |
548 (self.event_time(), self.deferred, | |
549 len(self.eventq))) | |
550 for wpath, evts in sorted(self.eventq.iteritems()): | |
551 for evt in evts: | |
552 self.deferred_event(wpath, evt) | |
553 self.eventq.clear() | |
554 self.deferred = 0 | |
555 self.timeout = None | 543 self.timeout = None |
556 | 544 |
557 def shutdown(self): | 545 def shutdown(self): |
558 self.watcher.close() | 546 self.watcher.close() |
559 | 547 |