You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by Sam Ruby <ru...@apache.org> on 2016/03/14 15:35:15 UTC

[whimsy.git] [1/1] Commit 73039e6: switch from per process mutex to system wide flock

Commit 73039e6e2d3cb5c00add9e9c10a45b60bbf76fac:
    switch from per process mutex to system wide flock
    needs more tweaks as flock updates mtime


Branch: refs/heads/master
Author: Sam Ruby <ru...@intertwingly.net>
Committer: Sam Ruby <ru...@intertwingly.net>
Pusher: rubys <ru...@apache.org>

------------------------------------------------------------
www/board/agenda/models/agenda.rb                            | +++++++++++ ---
www/board/agenda/views/models/agenda.js.rb                   | + 
------------------------------------------------------------
52 changes: 42 additions, 10 deletions.
------------------------------------------------------------


diff --git a/www/board/agenda/models/agenda.rb b/www/board/agenda/models/agenda.rb
index 34c6de8..f38591c 100755
--- a/www/board/agenda/models/agenda.rb
+++ b/www/board/agenda/models/agenda.rb
@@ -3,9 +3,10 @@
 # Most of the heavy lifting is done by ASF::Board::Agenda in the whimsy-asf
 # gem.  This class is mainly focused on caching the results.
 #
+# This code also maintains a "working copy" of agendas when updates are
+# made that may not yet be reflected in the local svn checkout.
+#
 class Agenda
-  @@mutex = Mutex.new
-
   def self.[](file)
     IPC[file]
   end
@@ -16,8 +17,16 @@ def self.[]=(file, data)
 
   def self.update_cache(file, path, contents, quick)
     parsed = ASF::Board::Agenda.parse(contents, quick)
-    Agenda[file] = {mtime: (quick ? -1 : File.mtime(path)), parsed: parsed}
-    IPC.post type: :agenda, file: file unless quick
+    update = {mtime: (quick ? -1 : File.mtime(path)), parsed: parsed}
+    unless IPC[file] and IPC[file] == update
+      before = Agenda[file] and Agenda[file][:parsed]
+
+      Agenda[file] = update
+
+      unless quick or before == update[:parsed]
+        IPC.post type: :agenda, file: file, mtime: update[:mtime].to_f
+      end
+    end
   end
 
   def self.uptodate(file)
@@ -36,8 +45,15 @@ def self.parse(file, mode)
     
     return unless File.exist? path
 
+    # Does the working copy have more recent data?
+    working_copy = File.join(AGENDA_WORK, file)
+    if File.size?(working_copy) and File.mtime(working_copy) > File.mtime(path)
+      path = working_copy
+    end
+
     if Agenda[file][:mtime] != File.mtime(path)
-      @@mutex.synchronize do
+      File.open(working_copy, File::RDWR|File::CREAT, 0644) do |work_file|
+        work_file.flock(File::LOCK_EX)
         if Agenda[file][:mtime] != File.mtime(path)
           self.update_cache(file, path, File.read(path), mode == :quick)
         end
@@ -70,8 +86,12 @@ def self.update(file, message, retries=20, &block)
       auth = [['--username', env.user, '--password', env.password]]
     end
 
-    @@mutex.synchronize do
-      file.untaint if file =~ /\Aboard_\w+_[\d_]+\.txt\Z/
+    file.untaint if file =~ /\Aboard_\w+_[\d_]+\.txt\Z/
+
+    working_copy = File.join(AGENDA_WORK, file)
+
+    File.open(working_copy, File::RDWR|File::CREAT, 0644) do |work_file|
+      work_file.flock(File::LOCK_EX)
 
       # capture current version of the file
       path = File.join(FOUNDATION_BOARD, file)
@@ -98,11 +118,22 @@ def self.update(file, message, retries=20, &block)
         else
           commit_rc = 0
         end
+      else
+        output = IO.read(path)
       end
 
-      # update the cache if the file has changed
-      if output != baseline
-        self.update_cache(file, path, output, ENV['RACK_ENV'] == 'test')
+      # update the work file, and optionally the cache, if successful
+      if commit_rc == 0
+        work_file.rewind
+
+        if output != baseline
+          # update the cache if the file has changed
+          self.update_cache(file, path, output, ENV['RACK_ENV'] == 'test')
+          work_file.write(output)
+          work_file.flush
+        end
+
+        work_file.truncate(work_file.pos)
       end
 
       # return the result in the response
diff --git a/www/board/agenda/views/models/agenda.js.rb b/www/board/agenda/views/models/agenda.js.rb
index 14a40a2..0ca231d 100644
--- a/www/board/agenda/views/models/agenda.js.rb
+++ b/www/board/agenda/views/models/agenda.js.rb
@@ -11,6 +11,7 @@ class Agenda
   # (re)-load an agenda, creating instances for each item, and linking
   # each instance to their next and previous items.
   def self.load(list)
+    return unless list
     @@index.clear()
     prev = nil