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 collapse

POLL_INTERVAL =

seconds

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

Instance Method Summary collapse

Constructor Details

#initializeWatchInotify

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

#call(cooldown) ⇒ Object



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

def call(cooldown)
  yield
end

#changed_filesObject

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.


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

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

#closeObject



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

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

#remove_watch(file) ⇒ Object

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.


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

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

#start_watcherObject

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

#watch(file) ⇒ Object



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

#watcher_cycleObject

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