2 // NetBeagleQueryable.cs
4 // Copyright (C) 2005 Novell, Inc.
7 // Vijay K. Nanjundaswamy (knvijay@novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining a
12 // copy of this software and associated documentation files (the "Software"),
13 // to deal in the Software without restriction, including without limitation
14 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 // and/or sell copies of the Software, and to permit persons to whom the
16 // Software is furnished to do so, subject to the following conditions:
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 // DEALINGS IN THE SOFTWARE.
33 using System
.Threading
;
34 using System
.Collections
;
39 namespace Beagle
.Daemon
{
41 [QueryableFlavor (Name
="NetworkedBeagle", Domain
=QueryDomain
.Global
, RequireInotify
=false)]
42 public class NetworkedBeagle
: IQueryable
44 static Logger log
= Logger
.Get ("NetworkedBeagle");
45 static readonly string NetBeagleConfigFile
= "netbeagle.cfg";
46 public static readonly string BeagleNetPrefix
= "netbeagle://";
47 public static bool NetBeagleListActive
= false;
49 ArrayList NetBeagleList
;
51 public NetworkedBeagle ()
53 NetBeagleList
= new ArrayList ();
54 NetBeagleListActive
= false;
57 /////////////////////////////////////////////////////////////////////////////////////////
58 private static Hashtable requestTable
= Hashtable
.Synchronized(new Hashtable());
59 private static Hashtable timerTable
= Hashtable
.Synchronized(new Hashtable());
61 private static int TimerInterval
= 15000; //15 sec timer
62 private static int RequestCacheTime
= 20; //Cache requests for 5 minutes
64 private static System
.Timers
.Timer cTimer
= null;
66 static NetworkedBeagle () {
67 cTimer
= new System
.Timers
.Timer(TimerInterval
);
68 cTimer
.Elapsed
+= new ElapsedEventHandler(TimerEventHandler
);
69 cTimer
.AutoReset
= true;
70 cTimer
.Enabled
= false;
77 /////////////////////////////////////////////////////////////////////////////////////////
79 get { return "NetworkedBeagle"; }
84 SetupNetBeagleList ();
85 Conf
.Subscribe (typeof (Conf
.NetworkingConfig
), new Conf
.ConfigUpdateHandler (NetBeagleConfigurationChanged
));
88 void SetupNetBeagleList ()
90 //First check for ~/.beagle/config/networking.xml configuration
91 ArrayList NetBeagleNodes
= Conf
.Networking
.NetBeagleNodes
;
93 if ((NetBeagleNodes
!= null) && (NetBeagleNodes
.Count
> 0)) {
95 foreach (string nb
in NetBeagleNodes
) {
96 if (nb
== null || nb
== "")
98 string[] data
= nb
.Split (':');
99 if (data
.Length
< 2) {
100 log
.Warn("NetBeagleQueryable: Ignoring improper NetBeagle entry: {0}", nb
);
103 string host
= data
[0];
104 string port
= data
[1];
105 NetBeagleList
.Add (new NetBeagleHandler (host
, port
, this));
108 if (NetBeagleList
.Count
> 0) {
109 NetBeagleListActive
= true;
110 if (File
.Exists (Path
.Combine (PathFinder
.StorageDir
, NetBeagleConfigFile
)))
112 log
.Warn("NetBeagleQueryable: Duplicate configuration of networked Beagles detected!");
113 log
.Info("NetBeagleQueryable: Remove '~/.beagle/netbeagle.cfg' file. Use 'beagle-config' instead to setup networked Beagle nodes.");
114 log
.Info("Using ~/.beagle/config/networking.xml");
120 //Fallback to ~/.beagle/netbeagle.cfg
121 if (!File
.Exists (Path
.Combine (PathFinder
.StorageDir
, NetBeagleConfigFile
)))
124 StreamReader reader
= new StreamReader(Path
.Combine
125 (PathFinder
.StorageDir
, NetBeagleConfigFile
));
128 while ( ((entry
= reader
.ReadLine ()) != null) && (entry
.Trim().Length
> 1)) {
130 if ((entry
[0] != '#') && (entry
.IndexOf(':') > 0)) {
131 string[] data
= entry
.Split (':');
132 if (data
.Length
< 2) {
133 log
.Warn("NetBeagleQueryable: Ignoring improper NetBeagle entry: {0}", entry
);
137 string host
= data
[0];
138 string port
= data
[1];
139 NetBeagleList
.Add (new NetBeagleHandler (host
, port
, this));
143 if (NetBeagleList
.Count
> 0) {
144 NetBeagleListActive
= true;
145 //log.Warn("NetBeagleQueryable: 'netbeagle.cfg' based configuration deprecated.\n Use 'beagle-config' or 'beagle-settings' instead to configure Networked Beagles");
146 log
.Warn("NetBeagleQueryable: 'netbeagle.cfg' based configuration deprecated.\n Use 'beagle-config' instead to configure Networked Beagles");
150 private void NetBeagleConfigurationChanged (Conf
.Section section
)
152 Logger
.Log
.Info("NetBeagleConfigurationChanged EventHandler invoked");
153 if (! (section
is Conf
.NetworkingConfig
))
156 Conf
.NetworkingConfig nc
= (Conf
.NetworkingConfig
) section
;
158 //if (nc.NetBeagleNodes.Count == 0)
161 ArrayList newList
= new ArrayList();
162 foreach (string nb
in nc
.NetBeagleNodes
) {
163 if (nb
== null || nb
== "")
165 string[] data
= nb
.Split (':');
166 if (data
.Length
< 2) {
167 log
.Warn("NetBeagleQueryable: Ignoring improper NetBeagle entry: {0}", nb
);
170 string host
= data
[0];
171 string port
= data
[1];
172 newList
.Add (new NetBeagleHandler (host
, port
, this));
176 NetBeagleList
= newList
;
177 NetBeagleListActive
= (newList
.Count
== 0) ? false:true;
181 public bool AcceptQuery (Query query
)
183 if (query
.Text
.Count
<= 0)
186 if (! query
.AllowsDomain (QueryDomain
.Global
))
192 public string GetSnippet (string[] query_terms
, Hit hit
)
196 if (hit
is NetworkHit
)
197 s
= ((NetworkHit
)hit
).snippet
;
202 public int GetItemCount ()
207 public QueryableStatus
GetQueryableStatus ()
210 QueryableStatus status
= new QueryableStatus ();
214 public void DoQuery (Query query
,IQueryResult result
,
215 IQueryableChangeData changeData
)
217 if (NetBeagleList
.Count
== 0)
220 ArrayList resultHandleList
= new ArrayList();
221 lock (NetBeagleList
) {
222 log
.Debug("NetBeagleQueryable: DoQuery ... Starting NetBeagleHandler queries");
223 foreach (NetBeagleHandler nb
in NetBeagleList
)
225 IAsyncResult iar
= nb
.DoQuery (query
, result
, changeData
);
226 resultHandleList
.Add (iar
);
231 foreach (IAsyncResult iar
in resultHandleList
)
232 while (! ((ReqContext
)(iar
.AsyncState
)).RequestProcessed
) {
234 if (++i
> 20) //Don't wait more than 20 secs
238 log
.Debug("NetBeagleQueryable:DoQuery ... Done");
241 /////////////////////////////////////////////////////////////////////////////////////////
242 //Methods related to checking & caching of networked search requests,
243 //to prevent duplicate queries in cascaded network operation
245 class TimerHopCount
{
249 public TimerHopCount (int h
) {
251 this.ttl
= RequestCacheTime
;
261 //set {hops = value;}
265 public static int AddRequest(Query q
)
270 if (requestTable
.Contains(q
))
271 return (int) requestTable
[q
];
273 searchId
= System
.Guid
.NewGuid().GetHashCode();
276 searchId
= -searchId
;
278 requestTable
.Add(q
, searchId
);
279 timerTable
.Add(q
, new TimerHopCount(1));
281 if (!cTimer
.Enabled
) {
283 log
.Debug("CachedRequestCleanupTimer started");
290 public static int HopCount(Query q
)
296 if (timerTable
.Contains(q
))
297 hops
= ((TimerHopCount
) timerTable
[q
]).Hops
;
303 public static void CacheRequest(Query q
, int searchId
, int hops
)
307 if (requestTable
.Contains(q
)) {
308 requestTable
[q
] = searchId
;
309 timerTable
[q
] = new TimerHopCount(hops
);
312 requestTable
.Add(q
, searchId
);
313 timerTable
.Add(q
, new TimerHopCount(hops
));
316 if (!cTimer
.Enabled
) {
318 log
.Info("CachedRequestCleanupTimer started");
321 log
.Info("CacheRequest: HopCount = " + hops
);
325 public static bool IsCachedRequest(int searchId
)
330 cached
= requestTable
.ContainsValue(searchId
);
335 private static void TimerEventHandler(object source
, ElapsedEventArgs e
)
339 ArrayList keys
= new ArrayList();
340 keys
.AddRange(timerTable
.Keys
);
342 foreach (Query q
in keys
)
344 TimerHopCount thc
= (TimerHopCount
) timerTable
[q
];
355 if ((c
% 4) == 0) //Log status every 1 minute
356 log
.Info("CachedRequestCleanupTimer-EventHandler: requestTable has {0} elements, Last entry count={1}", requestTable
.Count
, c
);
358 if (timerTable
.Count
== 0) {
360 log
.Info("Stopping CachedRequestCleanupTimer");
364 private static void RemoveRequest(Query q
)
368 if (requestTable
.Contains(q
))
369 requestTable
.Remove(q
);
371 if (timerTable
.Contains(q
))
372 timerTable
.Remove(q
);