Class: Ramaze::Reloader::WatchInotify

Inherits:
Object
  • Object
show all
Defined in:
lib/ramaze/reloader/watch_inotify.rb

Overview

TODO: * There seems to be a problem somewhere that I couldn't identify yet, a file has to be modified twice initially to make it show up as modified here, subsequent changes work just fine. The only workaround I could find right now would be to read/write every single file, but that would be unexpected, irresponsible, and error-prone.

NOTE: * I have changed from using a Mutex to using a Queue, which uses a Mutex internally.

Constant Summary

POLL_INTERVAL =

seconds

2
NOTIFY_MASK =
RInotify::MODIFY | RInotify::IN_ONESHOT

Instance Method Summary (collapse)

Constructor Details

- (WatchInotify) initialize

Returns a new instance of WatchInotify



19
20
21
22
23
# File 'lib/ramaze/reloader/watch_inotify.rb', line 19

def initialize
  @watcher = RInotify.new
  @changed = Queue.new
  @watcher_thread = start_watcher
end

Instance Method Details

- (Object) call(cooldown)



25
26
27
# File 'lib/ramaze/reloader/watch_inotify.rb', line 25

def call(cooldown)
  yield
end

- (Object) changed_files

NOTE: We have to add the changed file again after we got a notification, I have no idea why, but using IN_ONESHOT should make sure that there is no memory leak in the C level even if we add a file again. There is a memory leak however in the watch_descriptors hash, since rinotify won't synchronize the contents properly and will only add to the hash, so we have to clean up ourselves.



74
75
76
77
78
79
80
81
# File 'lib/ramaze/reloader/watch_inotify.rb', line 74

def changed_files
  until @changed.empty?
    descriptor = @changed.shift
    file = @watcher.watch_descriptors.delete(descriptor)
    watch(file)
    yield(file)
  end
end

- (Object) close



61
62
63
64
65
# File 'lib/ramaze/reloader/watch_inotify.rb', line 61

def close
  @watcher_thread.terminate
  @watcher.close
  true
end

- (Object) remove_watch(file)

FIXME: Seems like this won't work due to some bug in the rinotify library. Would be cool if someone could make a FFI version.



57
58
59
# File 'lib/ramaze/reloader/watch_inotify.rb', line 57

def remove_watch(file)
  @watcher.rm_watch(file)
end

- (Object) start_watcher

TODO: define a finalizer to cleanup? -- reloader never calls #close



31
32
33
# File 'lib/ramaze/reloader/watch_inotify.rb', line 31

def start_watcher
  Thread.new{ loop{ watcher_cycle }}
end

- (Object) watch(file)



45
46
47
48
49
50
51
52
# File 'lib/ramaze/reloader/watch_inotify.rb', line 45

def watch(file)
  return if @watcher.watch_descriptors.has_value?(file)
  return unless File.exist?(file)

  @watcher.add_watch(file, NOTIFY_MASK)
rescue Errno::ENOENT
  retry
end

- (Object) watcher_cycle

Not much work here, we just have to empty the event queue and push the descriptors for reloading on next request.



37
38
39
40
41
42
43
# File 'lib/ramaze/reloader/watch_inotify.rb', line 37

def watcher_cycle
  return unless @watcher.wait_for_events(POLL_INTERVAL)

  @watcher.each_event do |event|
    @changed.push(event.watch_descriptor)
  end
end