2 // IndexSynchronization.cs
4 // Copyright (C) 2005-2006 Novell, Inc.
8 // Permission is hereby granted, free of charge, to any person obtaining a
9 // copy of this software and associated documentation files (the "Software"),
10 // to deal in the Software without restriction, including without limitation
11 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 // and/or sell copies of the Software, and to permit persons to whom the
13 // Software is furnished to do so, subject to the following conditions:
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24 // DEALINGS IN THE SOFTWARE.
29 using System
.Collections
;
30 using System
.Threading
;
34 namespace Beagle
.Daemon
{
36 public class IndexSynchronization
{
38 // 1 hour synchronization period
39 static private int sync_interval_in_minutes
= 60;
41 // Synchonization lock object
42 static private object synchronization_lock
= new object ();
44 // Original index storage directory
45 static private string remote_index_dir
= Path
.Combine (PathFinder
.StorageDir
, "Indexes");
47 // Locally sync'd storage directory
48 static private string local_index_dir
= PathFinder
.IndexDir
;
50 ////////////////////////////////////////////////////////////////
52 public enum SynchronizationTarget
{
57 static public void Initialize ()
59 Logger
.Log
.Debug ("Initializing index synchronization");
61 if (! Directory
.Exists (remote_index_dir
))
62 Directory
.CreateDirectory (remote_index_dir
);
64 Log
.Debug ("Remote index storage dir {0} will be synchronized to temp local storage dir {1}", remote_index_dir
, local_index_dir
);
66 // Initial index synchronization
67 Synchronize (SynchronizationTarget
.Local
);
71 // Add the synchronization task to the scheduler
72 task
= Scheduler
.TaskFromHook (new Scheduler
.TaskHook (SynchronizeHook
));
73 task
.Tag
= "Synchronize Indexes";
74 task
.Priority
= Scheduler
.Priority
.Delayed
;
75 task
.TriggerTime
= DateTime
.Now
.AddMinutes (sync_interval_in_minutes
);
76 task
.Source
= synchronization_lock
;
77 Scheduler
.Global
.Add (task
);
79 // Set up the shutdown synchronization task
80 task
= Scheduler
.TaskFromHook (new Scheduler
.TaskHook (ShutdownHook
));
81 task
.Tag
= "Synchronize Indexes on Shutdown";
82 task
.Priority
= Scheduler
.Priority
.Shutdown
;
83 task
.Source
= synchronization_lock
;
84 Scheduler
.Global
.Add (task
);
87 ////////////////////////////////////////////////////////////////
89 static public void Synchronize (SynchronizationTarget target
)
91 Stopwatch watch
= new Stopwatch ();
94 lock (synchronization_lock
) {
95 Logger
.Log
.Debug ("Synchronizing... (target={0})", target
);
97 DirectoryInfo source_directory
, target_directory
;
98 source_directory
= new DirectoryInfo ((target
== SynchronizationTarget
.Local
) ? remote_index_dir
: local_index_dir
);
99 target_directory
= new DirectoryInfo ((target
== SynchronizationTarget
.Local
) ? local_index_dir
: remote_index_dir
);
101 if (SynchronizeDirectory (source_directory
, target_directory
))
102 Logger
.Log
.Debug ("Synchronized successfully in {0}", watch
);
106 ////////////////////////////////////////////////////////////////
108 static private void SynchronizeHook (Scheduler
.Task task
)
111 Synchronize (SynchronizationTarget
.Remote
);
112 } catch (Exception ex
) {
113 Logger
.Log
.Error (ex
, "Caught exception while synchronizing");
116 task
.Reschedule
= true;
117 task
.TriggerTime
= DateTime
.Now
.AddMinutes (sync_interval_in_minutes
);
120 static private void ShutdownHook (Scheduler
.Task task
)
123 Synchronize (SynchronizationTarget
.Remote
);
125 // FIXME: This may not be safe to do here
126 Logger
.Log
.Debug ("Purging locally synchronized indexes");
127 Directory
.Delete (local_index_dir
, true);
128 } catch (Exception ex
) {
129 Logger
.Log
.Error (ex
, "Caught exception while doing shutdown synchronization");
133 ////////////////////////////////////////////////////////////////
135 // FIXME: Non-Getto synchronization
136 static private bool SynchronizeDirectory (DirectoryInfo source_directory
,
137 DirectoryInfo target_directory
)
139 if (! source_directory
.Exists
)
140 throw new Exception ("Synchronization error: Source directory does not exist");
142 DirectoryInfo target_directory_temp
, target_directory_trash
;
144 // Setup directories for the copy/move/move/delete procedure
145 target_directory_temp
= new DirectoryInfo (target_directory
.FullName
+ ".tmp");
146 target_directory_trash
= new DirectoryInfo (target_directory
.FullName
+ ".trash");
148 if (target_directory_temp
.Exists
)
149 target_directory_temp
.Delete (true);
150 target_directory_temp
.Create ();
153 // Copy the directory structure and files
154 CopyDirectoryRecursively (source_directory
, target_directory_temp
);
156 if (target_directory_trash
.Exists
)
157 target_directory_trash
.Delete (true);
159 target_directory
.MoveTo (target_directory_trash
.FullName
);
160 target_directory_temp
.MoveTo (target_directory
.FullName
);
162 target_directory_trash
.Delete (true);
163 } catch (Exception ex
) {
164 Logger
.Log
.Error (ex
, "Caught error while synchronizing directory");
171 static private void CopyDirectoryRecursively (DirectoryInfo source_directory
,
172 DirectoryInfo target_directory
)
174 if (!target_directory
.Exists
)
175 target_directory
.Create ();
177 foreach (FileInfo source_file
in DirectoryWalker
.GetFileInfos (source_directory
)) {
178 FileInfo target_file
= new FileInfo (Path
.Combine (target_directory
.FullName
, source_file
.Name
));
180 // FIXME: Don't hard code filenames - Mono.Posix.StatMode.Regular
181 if (source_file
.Name
.IndexOf ("socket") != -1 ||
182 source_file
.Name
.EndsWith ("-journal"))
185 File
.Copy (source_file
.FullName
, target_file
.FullName
, true);
188 foreach (DirectoryInfo source_child_directory
in DirectoryWalker
.GetDirectoryInfos (source_directory
)) {
189 DirectoryInfo target_child_directory
= new DirectoryInfo (Path
.Combine (target_directory
.FullName
, source_child_directory
.Name
));
191 CopyDirectoryRecursively (source_child_directory
,
192 target_child_directory
);