Sublime Forum

[Bug] Multiple Disk-Writes on file save

#1

It seems that when saving a file in Linux (ubuntu 11.04) Sublime Text 2 writes to the disk twice.

The specific issue this causes for me is that it causes a problem when using guard https://github.com/guard/guard to monitor my source tree for changes. Guard (on linux) uses rb-inotify to watch for changes and then fires events such as building coffeescript, scss, or triggering a livereload event in your browser.

Here is the bit of ruby i was using to test with:

require 'rb-inotify'

notifier = INotify::Notifier.new
notifier.watch(".", :modify) do |event|
    puts "Catched event #{ event.inspect }"
end
notifier.run

Here are the events it was triggering:

Catched event #<INotify::Event:0x7fde939252b0 @notifier=#<INotify::Notifier:0x7fde95035f18 @watchers={1=>#<INotify::Watcher:0x7fde93925558 @path="coffee", @notifier=#<INotify::Notifier:0x7fde95035f18 ...>, @flags=:modify], @callback=#<Proc:0x00007fde95036828@test.rb:5>, @id=1>}, @stop=false, @fd=3>, @related=], @native=#<INotify::Native::Event:0x7fde93925260>, @watcher_id=1, @name="script.coffee", @cookie=0, @watcher=#<INotify::Watcher:0x7fde93925558 @path="coffee", @notifier=#<INotify::Notifier:0x7fde95035f18 @watchers={1=>#<INotify::Watcher:0x7fde93925558 ...>}, @stop=false, @fd=3>, @flags=:modify], @callback=#<Proc:0x00007fde95036828@test.rb:5>, @id=1>>

Catched event #<INotify::Event:0x7fde93924590 @notifier=#<INotify::Notifier:0x7fde95035f18 @watchers={1=>#<INotify::Watcher:0x7fde93925558 @path="coffee", @notifier=#<INotify::Notifier:0x7fde95035f18 ...>, @flags=:modify], @callback=#<Proc:0x00007fde95036828@test.rb:5>, @id=1>}, @stop=false, @fd=3>, @related=], @native=#<INotify::Native::Event:0x7fde93922d30>, @watcher_id=1, @name="script.coffee", @cookie=0, @watcher=#<INotify::Watcher:0x7fde93925558 @path="coffee", @notifier=#<INotify::Notifier:0x7fde95035f18 @watchers={1=>#<INotify::Watcher:0x7fde93925558 ...>}, @stop=false, @fd=3>, @flags=:modify], @callback=#<Proc:0x00007fde95036828@test.rb:5>, @id=1>>

Let me know if there is any more info i can provide to track this down.

0 Likes

#2

Sublime Text 2 writes the file to disk once, using the standard C idiom of fopen, fwrite, then fclose.

You can verify this on linux with strace, which will show you the system calls a process makes. An except from saving the linux keymap file is:

open("/<longpath>/Default (Linux).sublime-keymap", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 16
fstat(16, {st_mode=S_IFREG|0644, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f610cba4000
write(16, "\n\t{ \"keys\": \"ctrl+shift+n\"], \""..., 4096) = 4096
write(16, "\"home\"], \"command\": \"move_to\", \""..., 4096) = 4096
write(16, "\"ctrl+shift+space\"], \"command\":"..., 4096) = 4096
write(16, "\": \"preceding_text\", \"operator\":"..., 4096) = 4096
write(16, "e },\n\t\t\t{ \"key\": \"selection_empt"..., 4096) = 4096
write(16, " },\n\t\t\t{ \"key\": \"selection_empty"..., 4096) = 4096
write(16, "rl+k\", \"ctrl+space\"], \"command\":"..., 1622) = 1622
close(16)                               = 0
munmap(0x7f610cba4000, 4096)            = 0

You can see here the syscalls corresponding to the above glibc function calls. At the application level, a single call to fwrite is made, which expands into several invocations of the write syscall, writing 4k blocks.

There are no further syscalls on that file, except for innocuous calls to stat.

I’d hazard a guess that your issue here is one of two things:

  • Another process or plugin is writing to the file
  • Guard isn’t interacting the inotify correctly, and is receiving duplicate notifications, or failing to coalesce multiple subscriptions

Your best bet is likely to run Sublime Text under strace, and verify for yourself what it’s writing. You can do this via:

strace sublime_text 2> strace_log.txt

kill the process after you’ve saved the file, and then scan through the strace output (there’ll be a lot of it) for the file name in question.

0 Likes

#3

Oh! thanks.

Yeah it looks like there is only one write call being made. Also using the inotify commandline tools it shows just one close_write operation. Must be an issue in guard or rb-inotify. Thanks for pointing me in the right direction.

0 Likes