From d1c3f8eef58b29eb8760eeb1ac03852a2387f927 Mon Sep 17 00:00:00 2001 From: Oren Hurvitz Date: Mon, 31 Mar 2014 11:53:12 +0300 Subject: Added assets service method AssetsExist(), which returns whether the given list of assets exist. This method is used to optimize sending assets with embedded assets: e.g., when a Hypergrid visitor takes an item into the inventory. --- OpenSim/Services/AssetService/AssetService.cs | 19 +++- OpenSim/Services/AssetService/XAssetService.cs | 11 ++- .../Connectors/Asset/AssetServicesConnector.cs | 21 +++++ .../Connectors/Asset/HGAssetServiceConnector.cs | 104 +++++++++++++-------- .../SimianGrid/SimianAssetServiceConnector.cs | 20 ++++ OpenSim/Services/Interfaces/IAssetService.cs | 7 ++ 6 files changed, 140 insertions(+), 42 deletions(-) (limited to 'OpenSim/Services') diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index 08fd3f8..0aefa16 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs @@ -153,9 +153,24 @@ namespace OpenSim.Services.AssetService return true; } + public virtual bool[] AssetsExist(string[] ids) + { + try + { + UUID[] uuid = Array.ConvertAll(ids, id => UUID.Parse(id)); + return m_Database.AssetsExist(uuid); + } + catch (Exception e) + { + m_log.Error("[ASSET SERVICE]: Exception getting assets ", e); + return new bool[ids.Length]; + } + } + public virtual string Store(AssetBase asset) { - if (!m_Database.ExistsAsset(asset.FullID)) + bool exists = m_Database.AssetsExist(new[] { asset.FullID })[0]; + if (!exists) { // m_log.DebugFormat( // "[ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.FullID, asset.Data.Length); @@ -186,4 +201,4 @@ namespace OpenSim.Services.AssetService return m_Database.Delete(id); } } -} \ No newline at end of file +} diff --git a/OpenSim/Services/AssetService/XAssetService.cs b/OpenSim/Services/AssetService/XAssetService.cs index 6047616..f58b769 100644 --- a/OpenSim/Services/AssetService/XAssetService.cs +++ b/OpenSim/Services/AssetService/XAssetService.cs @@ -175,9 +175,16 @@ namespace OpenSim.Services.AssetService return true; } + public virtual bool[] AssetsExist(string[] ids) + { + UUID[] uuid = Array.ConvertAll(ids, id => UUID.Parse(id)); + return m_Database.AssetsExist(uuid); + } + public virtual string Store(AssetBase asset) { - if (!m_Database.ExistsAsset(asset.FullID)) + bool exists = m_Database.AssetsExist(new[] { asset.FullID })[0]; + if (!exists) { // m_log.DebugFormat( // "[XASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.FullID, asset.Data.Length); @@ -217,4 +224,4 @@ namespace OpenSim.Services.AssetService m_ChainedAssetService.Delete(asset.ID); } } -} \ No newline at end of file +} diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 8b04d7f..32415e9 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs @@ -254,6 +254,27 @@ namespace OpenSim.Services.Connectors return true; } + public virtual bool[] AssetsExist(string[] ids) + { + string uri = m_ServerURI + "/get_assets_exist"; + + bool[] exist = null; + try + { + exist = SynchronousRestObjectRequester.MakeRequest("POST", uri, ids); + } + catch (Exception) + { + // This is most likely to happen because the server doesn't support this function, + // so just silently return "doesn't exist" for all the assets. + } + + if (exist == null) + exist = new bool[ids.Length]; + + return exist; + } + public string Store(AssetBase asset) { if (asset.Local) diff --git a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs index c395178..3710c86 100644 --- a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs @@ -36,6 +36,7 @@ using OpenSim.Framework; using OpenSim.Services.Interfaces; using OpenSim.Services.Connectors.Hypergrid; using OpenSim.Services.Connectors.SimianGrid; +using OpenMetaverse; namespace OpenSim.Services.Connectors { @@ -83,39 +84,6 @@ namespace OpenSim.Services.Connectors } } - private bool StringToUrlAndAssetID(string id, out string url, out string assetID) - { - url = String.Empty; - assetID = String.Empty; - - Uri assetUri; - - if (Uri.TryCreate(id, UriKind.Absolute, out assetUri) && - assetUri.Scheme == Uri.UriSchemeHttp) - { - // Simian - if (assetUri.Query != string.Empty) - { - NameValueCollection qscoll = HttpUtility.ParseQueryString(assetUri.Query); - assetID = qscoll["id"]; - if (assetID != null) - url = id.Replace(assetID, ""); // Malformed again, as simian expects - else - url = id; // !!! best effort - } - else // robust - { - url = "http://" + assetUri.Authority; - assetID = assetUri.LocalPath.Trim(new char[] { '/' }); - } - - return true; - } - - m_log.DebugFormat("[HG ASSET SERVICE]: Malformed URL {0}", id); - return false; - } - private IAssetService GetConnector(string url) { IAssetService connector = null; @@ -149,7 +117,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.Get(assetID); @@ -163,7 +131,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.GetCached(assetID); @@ -177,7 +145,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.GetMetadata(assetID); @@ -196,7 +164,7 @@ namespace OpenSim.Services.Connectors string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(id, out url, out assetID)) + if (Util.ParseForeignAssetID(id, out url, out assetID)) { IAssetService connector = GetConnector(url); return connector.Get(assetID, sender, handler); @@ -205,12 +173,72 @@ namespace OpenSim.Services.Connectors return false; } + + private struct AssetAndIndex + { + public UUID assetID; + public int index; + + public AssetAndIndex(UUID assetID, int index) + { + this.assetID = assetID; + this.index = index; + } + } + + public virtual bool[] AssetsExist(string[] ids) + { + // This method is a bit complicated because it works even if the assets belong to different + // servers; that requires sending separate requests to each server. + + // Group the assets by the server they belong to + + var url2assets = new Dictionary>(); + + for (int i = 0; i < ids.Length; i++) + { + string url = string.Empty; + string assetID = string.Empty; + + if (Util.ParseForeignAssetID(ids[i], out url, out assetID)) + { + if (!url2assets.ContainsKey(url)) + url2assets.Add(url, new List()); + url2assets[url].Add(new AssetAndIndex(UUID.Parse(assetID), i)); + } + } + + // Query each of the servers in turn + + bool[] exist = new bool[ids.Length]; + + foreach (string url in url2assets.Keys) + { + IAssetService connector = GetConnector(url); + lock (EndPointLock(connector)) + { + List curAssets = url2assets[url]; + string[] assetIDs = curAssets.ConvertAll(a => a.assetID.ToString()).ToArray(); + bool[] curExist = connector.AssetsExist(assetIDs); + + int i = 0; + foreach (AssetAndIndex ai in curAssets) + { + exist[ai.index] = curExist[i]; + ++i; + } + } + } + + return exist; + } + public string Store(AssetBase asset) { string url = string.Empty; string assetID = string.Empty; - if (StringToUrlAndAssetID(asset.ID, out url, out assetID)) + if (Util.ParseForeignAssetID(asset.ID, out url, out assetID)) { IAssetService connector = GetConnector(url); // Restore the assetID to a simple UUID diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs index 6f8d9ed..01cbf91 100644 --- a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs @@ -231,6 +231,26 @@ namespace OpenSim.Services.Connectors.SimianGrid return true; } + public bool[] AssetsExist(string[] ids) + { + if (String.IsNullOrEmpty(m_serverUrl)) + { + m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); + throw new InvalidOperationException(); + } + + bool[] exist = new bool[ids.Length]; + + for (int i = 0; i < ids.Length; i++) + { + AssetMetadata metadata = GetMetadata(ids[i]); + if (metadata != null) + exist[i] = true; + } + + return exist; + } + /// /// Creates a new asset /// diff --git a/OpenSim/Services/Interfaces/IAssetService.cs b/OpenSim/Services/Interfaces/IAssetService.cs index 3c469c6..8f1e039 100644 --- a/OpenSim/Services/Interfaces/IAssetService.cs +++ b/OpenSim/Services/Interfaces/IAssetService.cs @@ -75,6 +75,13 @@ namespace OpenSim.Services.Interfaces /// /// True if the id was parseable, false otherwise bool Get(string id, Object sender, AssetRetrieved handler); + + /// + /// Check if assets exist in the database. + /// + /// The assets' IDs + /// For each asset: true if it exists, false otherwise + bool[] AssetsExist(string[] ids); /// /// Creates a new asset -- cgit v1.1