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