opensim-development – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 eva 1 /*
2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of the OpenSimulator Project nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27  
28 using System;
29 using System.Reflection;
30 using log4net;
31 using Mono.Addins;
32 using Nini.Config;
33 using OpenSim.Framework;
34 using OpenSim.Region.Framework.Interfaces;
35 using OpenSim.Region.Framework.Scenes;
36  
37 namespace OpenSim.Region.CoreModules.Asset
38 {
39 /// <summary>
40 /// Cenome memory asset cache.
41 /// </summary>
42 /// <remarks>
43 /// <para>
44 /// Cache is enabled by setting "AssetCaching" configuration to value "CenomeMemoryAssetCache".
45 /// When cache is successfully enable log should have message
46 /// "[ASSET CACHE]: Cenome asset cache enabled (MaxSize = XXX bytes, MaxCount = XXX, ExpirationTime = XXX)".
47 /// </para>
48 /// <para>
49 /// Cache's size is limited by two parameters:
50 /// maximal allowed size in bytes and maximal allowed asset count. When new asset
51 /// is added to cache that have achieved either size or count limitation, cache
52 /// will automatically remove less recently used assets from cache. Additionally
53 /// asset's lifetime is controlled by expiration time.
54 /// </para>
55 /// <para>
56 /// <list type="table">
57 /// <listheader>
58 /// <term>Configuration</term>
59 /// <description>Description</description>
60 /// </listheader>
61 /// <item>
62 /// <term>MaxSize</term>
63 /// <description>Maximal size of the cache in bytes. Default value: 128MB (134 217 728 bytes).</description>
64 /// </item>
65 /// <item>
66 /// <term>MaxCount</term>
67 /// <description>Maximal count of assets stored to cache. Default value: 4096 assets.</description>
68 /// </item>
69 /// <item>
70 /// <term>ExpirationTime</term>
71 /// <description>Asset's expiration time in minutes. Default value: 30 minutes.</description>
72 /// </item>
73 /// </list>
74 /// </para>
75 /// </remarks>
76 /// <example>
77 /// Enabling Cenome Asset Cache:
78 /// <code>
79 /// [Modules]
80 /// AssetCaching = "CenomeMemoryAssetCache"
81 /// </code>
82 /// Setting size and expiration time limitations:
83 /// <code>
84 /// [AssetCache]
85 /// ; 256 MB (default: 134217728)
86 /// MaxSize = 268435456
87 /// ; How many assets it is possible to store cache (default: 4096)
88 /// MaxCount = 16384
89 /// ; Expiration time - 1 hour (default: 30 minutes)
90 /// ExpirationTime = 60
91 /// </code>
92 /// </example>
93 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "CenomeMemoryAssetCache")]
94 public class CenomeMemoryAssetCache : IImprovedAssetCache, ISharedRegionModule
95 {
96 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
97  
98 /// <summary>
99 /// Cache's default maximal asset count.
100 /// </summary>
101 /// <remarks>
102 /// <para>
103 /// Assuming that average asset size is about 32768 bytes.
104 /// </para>
105 /// </remarks>
106 public const int DefaultMaxCount = 4096;
107  
108 /// <summary>
109 /// Default maximal size of the cache in bytes
110 /// </summary>
111 /// <remarks>
112 /// <para>
113 /// 128MB = 128 * 1024^2 = 134 217 728 bytes.
114 /// </para>
115 /// </remarks>
116 public const long DefaultMaxSize = 134217728;
117  
118 /// <summary>
119 /// Asset's default expiration time in the cache.
120 /// </summary>
121 public static readonly TimeSpan DefaultExpirationTime = TimeSpan.FromMinutes(30.0);
122  
123 /// <summary>
124 /// Cache object.
125 /// </summary>
126 private ICnmCache<string, AssetBase> m_cache;
127  
128 /// <summary>
129 /// Count of cache commands
130 /// </summary>
131 private int m_cachedCount;
132  
133 /// <summary>
134 /// How many gets before dumping statistics
135 /// </summary>
136 /// <remarks>
137 /// If 0 or less, then disabled.
138 /// </remarks>
139 private int m_debugEpoch;
140  
141 /// <summary>
142 /// Is Cenome asset cache enabled.
143 /// </summary>
144 private bool m_enabled;
145  
146 /// <summary>
147 /// Count of get requests
148 /// </summary>
149 private int m_getCount;
150  
151 /// <summary>
152 /// How many hits
153 /// </summary>
154 private int m_hitCount;
155  
156 /// <summary>
157 /// Initialize asset cache module, with custom parameters.
158 /// </summary>
159 /// <param name="maximalSize">
160 /// Cache's maximal size in bytes.
161 /// </param>
162 /// <param name="maximalCount">
163 /// Cache's maximal count of assets.
164 /// </param>
165 /// <param name="expirationTime">
166 /// Asset's expiration time.
167 /// </param>
168 protected void Initialize(long maximalSize, int maximalCount, TimeSpan expirationTime)
169 {
170 if (maximalSize <= 0 || maximalCount <= 0)
171 {
172 //m_log.Debug("[ASSET CACHE]: Cenome asset cache is not enabled.");
173 m_enabled = false;
174 return;
175 }
176  
177 if (expirationTime <= TimeSpan.Zero)
178 {
179 // Disable expiration time
180 expirationTime = TimeSpan.MaxValue;
181 }
182  
183 // Create cache and add synchronization wrapper over it
184 m_cache =
185 CnmSynchronizedCache<string, AssetBase>.Synchronized(new CnmMemoryCache<string, AssetBase>(
186 maximalSize, maximalCount, expirationTime));
187 m_enabled = true;
188 m_log.DebugFormat(
189 "[ASSET CACHE]: Cenome asset cache enabled (MaxSize = {0} bytes, MaxCount = {1}, ExpirationTime = {2})",
190 maximalSize,
191 maximalCount,
192 expirationTime);
193 }
194  
195 #region IImprovedAssetCache Members
196  
197 public bool Check(string id)
198 {
199 AssetBase asset;
200  
201 // XXX:This is probably not an efficient implementation.
202 return m_cache.TryGetValue(id, out asset);
203 }
204  
205 /// <summary>
206 /// Cache asset.
207 /// </summary>
208 /// <param name="asset">
209 /// The asset that is being cached.
210 /// </param>
211 public void Cache(AssetBase asset)
212 {
213 if (asset != null)
214 {
215 // m_log.DebugFormat("[CENOME ASSET CACHE]: Caching asset {0}", asset.ID);
216  
217 long size = asset.Data != null ? asset.Data.Length : 1;
218 m_cache.Set(asset.ID, asset, size);
219 m_cachedCount++;
220 }
221  
222 }
223  
224 /// <summary>
225 /// Clear asset cache.
226 /// </summary>
227 public void Clear()
228 {
229 m_cache.Clear();
230 }
231  
232 /// <summary>
233 /// Expire (remove) asset stored to cache.
234 /// </summary>
235 /// <param name="id">
236 /// The expired asset's id.
237 /// </param>
238 public void Expire(string id)
239 {
240 m_cache.Remove(id);
241 }
242  
243 /// <summary>
244 /// Get asset stored
245 /// </summary>
246 /// <param name="id">
247 /// The asset's id.
248 /// </param>
249 /// <returns>
250 /// Asset if it is found from cache; otherwise <see langword="null"/>.
251 /// </returns>
252 /// <remarks>
253 /// <para>
254 /// Caller should always check that is return value <see langword="null"/>.
255 /// Cache doesn't guarantee in any situation that asset is stored to it.
256 /// </para>
257 /// </remarks>
258 public AssetBase Get(string id)
259 {
260 m_getCount++;
261 AssetBase assetBase;
262 if (m_cache.TryGetValue(id, out assetBase))
263 m_hitCount++;
264  
265 if (m_getCount == m_debugEpoch)
266 {
267 m_log.DebugFormat(
268 "[ASSET CACHE]: Cached = {0}, Get = {1}, Hits = {2}%, Size = {3} bytes, Avg. A. Size = {4} bytes",
269 m_cachedCount,
270 m_getCount,
271 ((double) m_hitCount / m_getCount) * 100.0,
272 m_cache.Size,
273 m_cache.Size / m_cache.Count);
274 m_getCount = 0;
275 m_hitCount = 0;
276 m_cachedCount = 0;
277 }
278  
279 // if (null == assetBase)
280 // m_log.DebugFormat("[CENOME ASSET CACHE]: Asset {0} not in cache", id);
281  
282 return assetBase;
283 }
284  
285 #endregion
286  
287 #region ISharedRegionModule Members
288  
289 /// <summary>
290 /// Gets region module's name.
291 /// </summary>
292 public string Name
293 {
294 get { return "CenomeMemoryAssetCache"; }
295 }
296  
297 public Type ReplaceableInterface
298 {
299 get { return null; }
300 }
301  
302 /// <summary>
303 /// New region is being added to server.
304 /// </summary>
305 /// <param name="scene">
306 /// Region's scene.
307 /// </param>
308 public void AddRegion(Scene scene)
309 {
310 if (m_enabled)
311 scene.RegisterModuleInterface<IImprovedAssetCache>(this);
312 }
313  
314 /// <summary>
315 /// Close region module.
316 /// </summary>
317 public void Close()
318 {
319 m_enabled = false;
320 m_cache.Clear();
321 m_cache = null;
322 }
323  
324 /// <summary>
325 /// Initialize region module.
326 /// </summary>
327 /// <param name="source">
328 /// Configuration source.
329 /// </param>
330 public void Initialise(IConfigSource source)
331 {
332 m_cache = null;
333 m_enabled = false;
334  
335 IConfig moduleConfig = source.Configs[ "Modules" ];
336 if (moduleConfig == null)
337 return;
338  
339 string name = moduleConfig.GetString("AssetCaching");
340 //m_log.DebugFormat("[XXX] name = {0} (this module's name: {1}", name, Name);
341  
342 if (name != Name)
343 return;
344  
345 long maxSize = DefaultMaxSize;
346 int maxCount = DefaultMaxCount;
347 TimeSpan expirationTime = DefaultExpirationTime;
348  
349 IConfig assetConfig = source.Configs["AssetCache"];
350 if (assetConfig != null)
351 {
352 // Get optional configurations
353 maxSize = assetConfig.GetLong("MaxSize", DefaultMaxSize);
354 maxCount = assetConfig.GetInt("MaxCount", DefaultMaxCount);
355 expirationTime =
356 TimeSpan.FromMinutes(assetConfig.GetInt("ExpirationTime", (int)DefaultExpirationTime.TotalMinutes));
357  
358 // Debugging purposes only
359 m_debugEpoch = assetConfig.GetInt("DebugEpoch", 0);
360 }
361  
362 Initialize(maxSize, maxCount, expirationTime);
363 }
364  
365 /// <summary>
366 /// Initialization post handling.
367 /// </summary>
368 /// <remarks>
369 /// <para>
370 /// Modules can use this to initialize connection with other modules.
371 /// </para>
372 /// </remarks>
373 public void PostInitialise()
374 {
375 }
376  
377 /// <summary>
378 /// Region has been loaded.
379 /// </summary>
380 /// <param name="scene">
381 /// Region's scene.
382 /// </param>
383 /// <remarks>
384 /// <para>
385 /// This is needed for all module types. Modules will register
386 /// Interfaces with scene in AddScene, and will also need a means
387 /// to access interfaces registered by other modules. Without
388 /// this extra method, a module attempting to use another modules'
389 /// interface would be successful only depending on load order,
390 /// which can't be depended upon, or modules would need to resort
391 /// to ugly kludges to attempt to request interfaces when needed
392 /// and unnecessary caching logic repeated in all modules.
393 /// The extra function stub is just that much cleaner.
394 /// </para>
395 /// </remarks>
396 public void RegionLoaded(Scene scene)
397 {
398 }
399  
400 /// <summary>
401 /// Region is being removed.
402 /// </summary>
403 /// <param name="scene">
404 /// Region scene that is being removed.
405 /// </param>
406 public void RemoveRegion(Scene scene)
407 {
408 }
409  
410 #endregion
411 }
412 }