mantis 8890: waste CPU checking if asset id == Zero on get; several changes on region Asset connector

This commit is contained in:
UbitUmarov
2021-05-29 15:08:22 +01:00
parent 5c99e94b79
commit a23bf4eb1b
8 changed files with 158 additions and 90 deletions

View File

@@ -197,6 +197,8 @@ namespace OpenSim.Framework
public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool;
public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod;
public static readonly string UUIDZeroString = UUID.Zero.ToString();
public static bool IsPlatformMono
{
get { return Type.GetType("Mono.Runtime") != null; }

View File

@@ -835,7 +835,7 @@ namespace OpenSim.Framework
{
using (Stream respStream = response.GetResponseStream())
{
deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
deserial = XMLResponseHelper.LogAndDeserialize<TResponse>(
reqnum, respStream, response.ContentLength);
}
}
@@ -863,7 +863,7 @@ namespace OpenSim.Framework
{
using (Stream respStream = response.GetResponseStream())
{
deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
deserial = XMLResponseHelper.LogAndDeserialize<TResponse>(
reqnum, respStream, response.ContentLength);
}
}
@@ -1165,7 +1165,7 @@ namespace OpenSim.Framework
/// </returns>
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0);
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, 0, null);
}
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, IServiceAuth auth)
@@ -1187,34 +1187,11 @@ namespace OpenSim.Framework
/// </returns>
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0);
}
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, 0, auth);
}
/// Perform a synchronous REST request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
/// <param name="obj"></param>
/// <param name="pTimeout">
/// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
/// </param>
/// <param name="maxConnections"></param>
/// <returns>
/// The response. If there was an internal exception or the request timed out,
/// then the default(TResponse) is returned.
/// </returns>
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections)
{
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, maxConnections, null);
return MakeRequest<TRequest, TResponse>(verb, requestUrl, obj, pTimeout, null);
}
/// <summary>
/// Perform a synchronous REST request.
/// Perform a synchronous something request.
/// </summary>
/// <param name="verb"></param>
/// <param name="requestUrl"></param>
@@ -1222,17 +1199,16 @@ namespace OpenSim.Framework
/// <param name="pTimeout">
/// Request timeout in milliseconds. Timeout.Infinite indicates no timeout. If 0 is passed then the default HttpWebRequest timeout is used (100 seconds)
/// </param>
/// <param name="maxConnections"></param>
/// <returns>
/// The response. If there was an internal exception or the request timed out,
/// then the default(TResponse) is returned.
/// </returns>
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, int maxConnections, IServiceAuth auth)
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj, int pTimeout, IServiceAuth auth)
{
int reqnum = WebUtil.RequestNumber++;
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SRestObjectRequest {1} {2}",
m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SRestObjReq {1} {2}",
reqnum, verb, requestUrl);
int tickstart = Util.EnvironmentTickCount();
@@ -1247,17 +1223,14 @@ namespace OpenSim.Framework
if (auth != null)
auth.AddAuthorization(request.Headers);
request.AllowWriteStreamBuffering = false;
if (pTimeout != 0)
request.Timeout = pTimeout;
request.Method = verb;
}
catch (Exception e)
{
m_log.DebugFormat("[SRestObjectRequest]: Exception in creating request {0} {1}: {2}{3}",
m_log.DebugFormat("[SRestObjReq]: Exception in creating request {0} {1}: {2}{3}",
verb, requestUrl, e.Message, e.StackTrace);
return deserial;
}
@@ -1269,7 +1242,7 @@ namespace OpenSim.Framework
request.ContentType = "text/xml";
byte[] data;
XmlWriterSettings settings = new XmlWriterSettings(){Encoding = Util.UTF8};
XmlWriterSettings settings = new XmlWriterSettings() { Encoding = Util.UTF8 };
using (MemoryStream ms = new MemoryStream())
using (XmlWriter writer = XmlWriter.Create(ms, settings))
{
@@ -1293,13 +1266,12 @@ namespace OpenSim.Framework
catch (Exception e)
{
m_log.DebugFormat(
"[SRestObjectRequest]: Exception in making request {0} {1}: {2}{3}",
"[SRestObjReq]: Exception in making request {0} {1}: {2}{3}",
verb, requestUrl, e.Message, e.StackTrace);
return deserial;
}
int rcvlen = 0;
try
{
@@ -1310,13 +1282,13 @@ namespace OpenSim.Framework
rcvlen = (int)resp.ContentLength;
using (Stream respStream = resp.GetResponseStream())
{
deserial = XMLResponseHelper.LogAndDeserialize<TRequest, TResponse>(
deserial = XMLResponseHelper.LogAndDeserialize<TResponse>(
reqnum, respStream, resp.ContentLength);
}
}
else
{
m_log.DebugFormat("[SRestObjectRequest]: Oops! no content found in response stream from {0} {1}",
m_log.DebugFormat("[SRestObjReq]: Oops! no content found in response stream from {0} {1}",
verb, requestUrl);
}
}
@@ -1329,37 +1301,37 @@ namespace OpenSim.Framework
{
if (hwr.StatusCode == HttpStatusCode.Unauthorized)
{
m_log.ErrorFormat("[SRestObjectRequest]: {0} requires authentication",
m_log.ErrorFormat("[SRestObjReq]: {0} requires authentication",
requestUrl);
}
else if(hwr.StatusCode != HttpStatusCode.NotFound)
else if (hwr.StatusCode != HttpStatusCode.NotFound)
{
m_log.WarnFormat("[SRestObjectRequest]: {0} returned error: {1}",
m_log.WarnFormat("[SRestObjReq]: {0} returned error: {1}",
requestUrl, hwr.StatusCode);
}
}
else
m_log.ErrorFormat(
"[SRestObjectRequest]: WebException for {0} {1} {2} {3}",
"[SRestObjReq]: WebException for {0} {1} {2} {3}",
verb, requestUrl, typeof(TResponse).ToString(), e.Message);
}
}
catch (System.InvalidOperationException)
{
// This is what happens when there is invalid XML
m_log.DebugFormat("[SRestObjectRequest]: Invalid XML from {0} {1} {2}",
m_log.DebugFormat("[SRestObjReq]: Invalid XML from {0} {1} {2}",
verb, requestUrl, typeof(TResponse).ToString());
}
catch (Exception e)
{
m_log.DebugFormat("[SRestObjectRequest]: Exception on response from {0} {1}: {2}",
m_log.DebugFormat("[SRestObjReq]: Exception on response from {0} {1}: {2}",
verb, requestUrl, e.Message);
}
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime)
{
m_log.InfoFormat("[LOGHTTP]: Slow SRestObjectRequest {0} {1} {2} took {3}ms, {4}bytes",
m_log.InfoFormat("[LOGHTTP]: Slow SRestObjReq {0} {1} {2} took {3}ms, {4}bytes",
reqnum, verb, requestUrl, tickdiff, rcvlen);
}
else if (WebUtil.DebugLevel >= 4)
@@ -1369,11 +1341,112 @@ namespace OpenSim.Framework
}
return deserial;
}
public static TResponse MakeGetRequest<TResponse>(string requestUrl, int pTimeout, IServiceAuth auth)
{
int reqnum = WebUtil.RequestNumber++;
if (WebUtil.DebugLevel >= 3)
m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} SRestObjReq GET {2}", reqnum, requestUrl);
int tickstart = Util.EnvironmentTickCount();
TResponse deserial = default(TResponse);
HttpWebRequest request = null;
try
{
request = (HttpWebRequest)WebRequest.Create(requestUrl);
if (auth != null)
auth.AddAuthorization(request.Headers);
request.AllowWriteStreamBuffering = false;
if (pTimeout != 0)
request.Timeout = pTimeout;
request.Method = "GET";
}
catch (Exception e)
{
m_log.DebugFormat("[SRestObjReq]: Exception in creating GET request {0}: {1}{2}",
requestUrl, e.Message, e.StackTrace);
return deserial;
}
int rcvlen = 0;
try
{
using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
{
if (resp.ContentLength != 0)
{
rcvlen = (int)resp.ContentLength;
using (Stream respStream = resp.GetResponseStream())
{
deserial = XMLResponseHelper.LogAndDeserialize<TResponse>(
reqnum, respStream, resp.ContentLength);
}
}
else
{
m_log.DebugFormat("[SRestObjReq]: Oops! no content found in response stream from GET {0}",
requestUrl);
}
}
}
catch (WebException e)
{
using (HttpWebResponse hwr = (HttpWebResponse)e.Response)
{
if (hwr != null)
{
if (hwr.StatusCode == HttpStatusCode.Unauthorized)
{
m_log.ErrorFormat("[SRestObjReq]: GET {0} requires authentication",
requestUrl);
}
else if (hwr.StatusCode != HttpStatusCode.NotFound)
{
m_log.WarnFormat("[SRestObjReq]: GET {0} returned error: {1}",
requestUrl, hwr.StatusCode);
}
}
else
m_log.ErrorFormat(
"[SRestObjReq]: WebException for GET {0} {1} {2}",
requestUrl, typeof(TResponse).ToString(), e.Message);
}
}
catch (System.InvalidOperationException)
{
// This is what happens when there is invalid XML
m_log.DebugFormat("[SRestObjReq]: Invalid XML from GET {0} {1}",
requestUrl, typeof(TResponse).ToString());
}
catch (Exception e)
{
m_log.DebugFormat("[SRestObjReq]: Exception on response from GET {0}: {1}",
requestUrl, e.Message);
}
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
if (tickdiff > WebUtil.LongCallTime)
{
m_log.InfoFormat("[LOGHTTP]: Slow SRestObjReq GET {0} {1} took {2}ms, {3}bytes",
reqnum, requestUrl, tickdiff, rcvlen);
}
else if (WebUtil.DebugLevel >= 4)
{
m_log.DebugFormat("[LOGHTTP]: HTTP OUT {0} took {1}ms",
reqnum, tickdiff);
}
return deserial;
}
}
public static class XMLResponseHelper
{
public static TResponse LogAndDeserialize<TRequest, TResponse>(int reqnum, Stream respStream, long contentLength)
public static TResponse LogAndDeserialize<TResponse>(int reqnum, Stream respStream, long contentLength)
{
XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
if (WebUtil.DebugLevel >= 5)

View File

@@ -403,7 +403,6 @@ namespace OpenSim.Region.CoreModules.Asset
public void Cache(AssetBase asset, bool replace = false)
{
// TODO: Spawn this off to some seperate thread to do the actual writing
if (asset != null)
{
//m_log.DebugFormat("[FLOTSAM ASSET CACHE]: Caching asset with id {0}", asset.ID);
@@ -423,9 +422,7 @@ namespace OpenSim.Region.CoreModules.Asset
public void CacheNegative(string id)
{
if (m_negativeCacheEnabled)
{
m_negativeCache.Add(id, m_negativeExpiration);
}
}
/// <summary>
@@ -578,6 +575,9 @@ namespace OpenSim.Region.CoreModules.Asset
m_Requests++;
if (id.Equals(Util.UUIDZeroString))
return false;
if (m_negativeCache.ContainsKey(id))
return false;
@@ -696,6 +696,9 @@ namespace OpenSim.Region.CoreModules.Asset
if (m_MemoryCacheEnabled)
m_MemoryCache.Remove(id);
if (m_negativeCacheEnabled)
m_negativeCache.Remove(id);
if (m_FileCacheEnabled)
{
string filename = GetFileName(id);

View File

@@ -248,11 +248,18 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
}
}
if (id.Equals(Util.UUIDZeroString))
return false;
return m_AssetService.Get(id, sender, delegate (string assetID, object s, AssetBase a)
{
if ((a != null) && (m_Cache != null))
m_Cache.Cache(a);
if(m_Cache != null)
{
if (a == null)
m_Cache.CacheNegative(assetID);
else
m_Cache.Cache(a);
}
// if (null == a)
// m_log.WarnFormat("[LOCAL ASSET SERVICES CONNECTOR]: Could not asynchronously find asset with id {0}", id);
@@ -272,18 +279,10 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
if (asset.Local)
{
// m_log.DebugFormat(
// "[LOCAL ASSET SERVICE CONNECTOR]: Returning asset {0} {1} without querying database since status Temporary = {2}, Local = {3}",
// asset.Name, asset.ID, asset.Temporary, asset.Local);
return asset.ID;
}
else
{
// m_log.DebugFormat(
// "[LOCAL ASSET SERVICE CONNECTOR]: Passing {0} {1} on to asset service for storage, status Temporary = {2}, Local = {3}",
// asset.Name, asset.ID, asset.Temporary, asset.Local);
return m_AssetService.Store(asset);
}
}

View File

@@ -305,8 +305,8 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
return null;
}
if(StoreOnLocalGrid)
Store(asset);
else if (m_Cache != null)
StoreLocal(asset);
if (m_Cache != null)
m_Cache.Cache(asset);
}
else if (m_Cache != null)
@@ -345,6 +345,9 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Asset
if (asset == null)
{
if (id.Equals(Util.UUIDZeroString))
return false;
lock (m_AssetHandlers)
{
AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate (AssetBase _asset) { callBack(id, sender, _asset); });

View File

@@ -167,9 +167,7 @@ namespace OpenSim.Services.AssetService
{
//m_log.DebugFormat("[XASSET SERVICE]: Get asset async {0}", id);
UUID assetID;
if (!UUID.TryParse(id, out assetID))
if (!UUID.TryParse(id, out UUID assetID) || assetID == UUID.Zero)
return false;
AssetBase asset = Get(id);

View File

@@ -144,7 +144,7 @@ namespace OpenSim.Services.Connectors
{
string uri = m_ServerURI + "/assets/" + id;
asset = SynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0, m_Auth);
asset = SynchronousRestObjectRequester.MakeGetRequest<AssetBase>(uri, 0, m_Auth);
if (m_Cache != null)
{
if (asset != null)
@@ -177,7 +177,7 @@ namespace OpenSim.Services.Connectors
return null;
string uri = m_ServerURI + "/assets/" + id + "/metadata";
return SynchronousRestObjectRequester.MakeRequest<int, AssetMetadata>("GET", uri, 0, m_Auth);
return SynchronousRestObjectRequester.MakeGetRequest<AssetMetadata>(uri, 0, m_Auth);
}
@@ -269,7 +269,7 @@ namespace OpenSim.Services.Connectors
string id = r.id;
try
{
AssetBase a = SynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", r.uri, 0, 30000, m_Auth);
AssetBase a = SynchronousRestObjectRequester.MakeGetRequest<AssetBase>(r.uri, 30000, m_Auth);
if (a != null && m_Cache != null)
m_Cache.Cache(a);
@@ -338,12 +338,9 @@ namespace OpenSim.Services.Connectors
if (asset.FullID == UUID.Zero)
{
UUID uuid = UUID.Zero;
if (UUID.TryParse(asset.ID, out uuid))
{
if (UUID.TryParse(asset.ID, out UUID uuid))
asset.FullID = uuid;
}
if(asset.FullID == UUID.Zero)
else
{
m_log.WarnFormat("[Assets] Zero IDs: {0}",asset.Name);
asset.FullID = UUID.Random();
@@ -351,11 +348,9 @@ namespace OpenSim.Services.Connectors
}
}
if (m_Cache != null)
m_Cache.Cache(asset);
if (asset.Temporary || asset.Local)
{
m_Cache?.Cache(asset);
return asset.ID;
}
@@ -385,8 +380,7 @@ namespace OpenSim.Services.Connectors
// Placing this here, so that this work with old asset servers that don't send any reply back
// SynchronousRestObjectRequester returns somethins that is not an empty string
asset.ID = newID;
if (m_Cache != null)
m_Cache.Cache(asset);
m_Cache?.Cache(asset);
}
}
@@ -402,7 +396,6 @@ namespace OpenSim.Services.Connectors
m_Cache?.Get(id, out asset);
if (asset == null)
{
AssetMetadata metadata = GetMetadata(id);
@@ -426,19 +419,13 @@ namespace OpenSim.Services.Connectors
public virtual bool Delete(string id)
{
m_Cache?.Expire(id);
if (m_ServerURI == null)
return false;
string uri = m_ServerURI + "/assets/" + id;
if (SynchronousRestObjectRequester.MakeRequest<int, bool>("DELETE", uri, 0, m_Auth))
{
if (m_Cache != null)
m_Cache.Expire(id);
return true;
}
return false;
return SynchronousRestObjectRequester.MakeRequest<int, bool>("DELETE", uri, 0, m_Auth);
}
}
}

View File

@@ -128,6 +128,9 @@ namespace OpenSim.Services.Connectors
string url = string.Empty;
string assetID = string.Empty;
if (id.Equals(Util.UUIDZeroString))
return false;
if (Util.ParseForeignAssetID(id, out url, out assetID) > 0)
{
IAssetService connector = GetConnector(url);