Annotation of /trunk/AssetServer/Extensions/Memcached/MemcachedStorage.cs
Parent Directory
|
Revision Log
Revision 70 - (view) (download)
| 1 : | jhurliman | 49 | /* |
| 2 : | * Copyright (c) 2008 Intel Corporation | ||
| 3 : | * All rights reserved. | ||
| 4 : | * Redistribution and use in source and binary forms, with or without | ||
| 5 : | * modification, are permitted provided that the following conditions | ||
| 6 : | * are met: | ||
| 7 : | * | ||
| 8 : | * -- Redistributions of source code must retain the above copyright | ||
| 9 : | * notice, this list of conditions and the following disclaimer. | ||
| 10 : | * -- Redistributions in binary form must reproduce the above copyright | ||
| 11 : | * notice, this list of conditions and the following disclaimer in the | ||
| 12 : | * documentation and/or other materials provided with the distribution. | ||
| 13 : | * -- Neither the name of the Intel Corporation nor the names of its | ||
| 14 : | * contributors may be used to endorse or promote products derived from | ||
| 15 : | * this software without specific prior written permission. | ||
| 16 : | * | ||
| 17 : | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
| 18 : | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
| 19 : | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
| 20 : | * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS | ||
| 21 : | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
| 22 : | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
| 23 : | * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
| 24 : | * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
| 25 : | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
| 26 : | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
| 27 : | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| 28 : | */ | ||
| 29 : | |||
| 30 : | using System; | ||
| 31 : | using BeIT.MemCached; | ||
| 32 : | using ExtensionLoader; | ||
| 33 : | using ExtensionLoader.Config; | ||
| 34 : | using OpenMetaverse; | ||
| 35 : | |||
| 36 : | namespace AssetServer.Extensions | ||
| 37 : | { | ||
| 38 : | public class MemcachedStorage : IExtension<AssetServer>, IStorageProvider | ||
| 39 : | { | ||
| 40 : | const string EXTENSION_NAME = "MemcachedStorage"; // Used in metrics reporting | ||
| 41 : | |||
| 42 : | AssetServer server; | ||
| 43 : | MemcachedClient cacheClient; | ||
| 44 : | IStorageProvider storageBackend; | ||
| 45 : | |||
| 46 : | public MemcachedStorage() | ||
| 47 : | { | ||
| 48 : | } | ||
| 49 : | |||
| 50 : | #region Required Interfaces | ||
| 51 : | |||
| 52 : | public void Start(AssetServer server) | ||
| 53 : | { | ||
| 54 : | this.server = server; | ||
| 55 : | cacheClient = null; | ||
| 56 : | |||
| 57 : | try | ||
| 58 : | { | ||
| 59 : | IConfig memcacheConfig = server.ConfigFile.Configs["Memcached"]; | ||
| 60 : | |||
| 61 : | if (memcacheConfig.Contains("Servers")) | ||
| 62 : | { | ||
| 63 : | string[] servers = memcacheConfig.GetString("Servers").Split(','); | ||
| 64 : | |||
| 65 : | try | ||
| 66 : | { | ||
| 67 : | MemcachedClient.Setup("AssetServer", servers); | ||
| 68 : | cacheClient = MemcachedClient.GetInstance("AssetServer"); | ||
| 69 : | } | ||
| 70 : | catch (Exception ex) | ||
| 71 : | { | ||
| 72 : | Logger.Log.Error("Failed to connect to memcached: " + ex.Message); | ||
| 73 : | } | ||
| 74 : | } | ||
| 75 : | } | ||
| 76 : | catch (Exception) | ||
| 77 : | { | ||
| 78 : | Logger.Log.Error("Failed to load [Memcached] section from config file " + AssetServer.CONFIG_FILE); | ||
| 79 : | } | ||
| 80 : | |||
| 81 : | // Search through the loaded extensions for another IStorageProvider | ||
| 82 : | // that will serve as the fallback for the cache | ||
| 83 : | foreach (IExtension<AssetServer> extension in ExtensionLoader<AssetServer>.Extensions) | ||
| 84 : | { | ||
| 85 : | if (extension is IStorageProvider && extension != this) | ||
| 86 : | storageBackend = extension as IStorageProvider; | ||
| 87 : | } | ||
| 88 : | |||
| 89 : | if (storageBackend == null) | ||
| 90 : | Logger.Log.Warn("Memcached caching storage provider loaded with no fallback storage provider"); | ||
| 91 : | } | ||
| 92 : | |||
| 93 : | public void Stop() | ||
| 94 : | { | ||
| 95 : | } | ||
| 96 : | |||
| 97 : | jhurliman | 70 | public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata) |
| 98 : | jhurliman | 49 | { |
| 99 : | metadata = null; | ||
| 100 : | jhurliman | 70 | BackendResponse ret; |
| 101 : | jhurliman | 49 | string cacheID = assetID.ToString() + "-metadata"; |
| 102 : | |||
| 103 : | jhurliman | 69 | if (cacheClient != null) |
| 104 : | jhurliman | 49 | { |
| 105 : | jhurliman | 69 | byte[] data = cacheClient.Get(cacheID) as byte[]; |
| 106 : | if (data != null) | ||
| 107 : | jhurliman | 49 | { |
| 108 : | jhurliman | 69 | metadata = new Metadata(); |
| 109 : | metadata.Deserialize(data); | ||
| 110 : | jhurliman | 49 | } |
| 111 : | jhurliman | 69 | } |
| 112 : | jhurliman | 49 | |
| 113 : | jhurliman | 69 | if (metadata != null) |
| 114 : | { | ||
| 115 : | jhurliman | 70 | ret = BackendResponse.Success; |
| 116 : | jhurliman | 69 | } |
| 117 : | else if (storageBackend != null) | ||
| 118 : | { | ||
| 119 : | jhurliman | 70 | BackendResponse response = storageBackend.TryFetchMetadata(assetID, out metadata); |
| 120 : | jhurliman | 49 | |
| 121 : | jhurliman | 70 | if (response == BackendResponse.Success && cacheClient != null) |
| 122 : | jhurliman | 49 | { |
| 123 : | jhurliman | 69 | if (cacheClient.Set(cacheID, metadata.SerializeToBytes())) |
| 124 : | Logger.Log.Debug("Cached " + cacheID); | ||
| 125 : | jhurliman | 49 | } |
| 126 : | jhurliman | 69 | |
| 127 : | ret = response; | ||
| 128 : | jhurliman | 49 | } |
| 129 : | else | ||
| 130 : | { | ||
| 131 : | jhurliman | 70 | ret = BackendResponse.Failure; |
| 132 : | jhurliman | 49 | } |
| 133 : | |||
| 134 : | jhurliman | 69 | server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now); |
| 135 : | jhurliman | 49 | return ret; |
| 136 : | } | ||
| 137 : | |||
| 138 : | jhurliman | 70 | public BackendResponse TryFetchData(UUID assetID, out byte[] assetData) |
| 139 : | jhurliman | 49 | { |
| 140 : | assetData = null; | ||
| 141 : | jhurliman | 70 | BackendResponse ret; |
| 142 : | jhurliman | 49 | string cacheID = assetID.ToString(); |
| 143 : | |||
| 144 : | jhurliman | 69 | if (cacheClient != null) |
| 145 : | assetData = cacheClient.Get(cacheID) as byte[]; | ||
| 146 : | |||
| 147 : | if (assetData != null) | ||
| 148 : | jhurliman | 49 | { |
| 149 : | jhurliman | 70 | ret = BackendResponse.Success; |
| 150 : | jhurliman | 69 | } |
| 151 : | else if (storageBackend != null) | ||
| 152 : | { | ||
| 153 : | jhurliman | 70 | BackendResponse response = storageBackend.TryFetchData(assetID, out assetData); |
| 154 : | jhurliman | 49 | |
| 155 : | jhurliman | 70 | if (response == BackendResponse.Success && cacheClient != null) |
| 156 : | jhurliman | 49 | { |
| 157 : | jhurliman | 69 | if (cacheClient.Set(cacheID, assetData)) |
| 158 : | Logger.Log.Debug("Cached " + cacheID); | ||
| 159 : | jhurliman | 49 | } |
| 160 : | |||
| 161 : | jhurliman | 69 | ret = response; |
| 162 : | jhurliman | 49 | } |
| 163 : | else | ||
| 164 : | { | ||
| 165 : | jhurliman | 70 | ret = BackendResponse.Failure; |
| 166 : | jhurliman | 49 | } |
| 167 : | |||
| 168 : | jhurliman | 69 | server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now); |
| 169 : | jhurliman | 49 | return ret; |
| 170 : | } | ||
| 171 : | |||
| 172 : | jhurliman | 70 | public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData) |
| 173 : | jhurliman | 49 | { |
| 174 : | metadata = null; | ||
| 175 : | |||
| 176 : | jhurliman | 70 | BackendResponse response = TryFetchData(assetID, out assetData); |
| 177 : | if (response == BackendResponse.Success) | ||
| 178 : | jhurliman | 69 | response = TryFetchMetadata(assetID, out metadata); |
| 179 : | jhurliman | 49 | |
| 180 : | return response; | ||
| 181 : | } | ||
| 182 : | |||
| 183 : | jhurliman | 70 | public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID) |
| 184 : | jhurliman | 49 | { |
| 185 : | assetID = metadata.ID = UUID.Random(); | ||
| 186 : | jhurliman | 69 | return TryCreateAsset(metadata, assetData); |
| 187 : | jhurliman | 49 | } |
| 188 : | |||
| 189 : | jhurliman | 70 | public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData) |
| 190 : | jhurliman | 49 | { |
| 191 : | jhurliman | 70 | BackendResponse ret; |
| 192 : | jhurliman | 49 | |
| 193 : | if (storageBackend != null) | ||
| 194 : | { | ||
| 195 : | jhurliman | 70 | BackendResponse response = storageBackend.TryCreateAsset(metadata, assetData); |
| 196 : | jhurliman | 49 | |
| 197 : | jhurliman | 70 | if (response == BackendResponse.Success && cacheClient != null) |
| 198 : | jhurliman | 49 | { |
| 199 : | // There is a high likelihood that an asset that was just uploaded (or its metdata) | ||
| 200 : | // will be fetched very soon. Call TryFetchDataMetadata to pre-emptively cache the | ||
| 201 : | // final stored data | ||
| 202 : | jhurliman | 69 | TryFetchDataMetadata(metadata.ID, out metadata, out assetData); |
| 203 : | jhurliman | 49 | } |
| 204 : | |||
| 205 : | ret = response; | ||
| 206 : | } | ||
| 207 : | else | ||
| 208 : | { | ||
| 209 : | jhurliman | 70 | ret = BackendResponse.Failure; |
| 210 : | jhurliman | 49 | } |
| 211 : | |||
| 212 : | // Don't log the storage to the metrics provider, the actual storage provider will do that | ||
| 213 : | return ret; | ||
| 214 : | } | ||
| 215 : | |||
| 216 : | jhurliman | 69 | public int ForEach(Action<Metadata> action, int start, int count) |
| 217 : | jhurliman | 49 | { |
| 218 : | // Can't iterate over memcached contents, pass this directly to the backend | ||
| 219 : | if (storageBackend != null) | ||
| 220 : | jhurliman | 69 | return storageBackend.ForEach(action, start, count); |
| 221 : | jhurliman | 49 | else |
| 222 : | return 0; | ||
| 223 : | } | ||
| 224 : | |||
| 225 : | #endregion Required Interfaces | ||
| 226 : | } | ||
| 227 : | } |
| ViewVC Help | |
| Powered by ViewVC 1.0.0 |

