missing file...

This commit is contained in:
UbitUmarov 2024-02-06 23:48:07 +00:00
parent 2e26b8a8bb
commit fbdb6c420f
1 changed files with 502 additions and 0 deletions

View File

@ -0,0 +1,502 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenMetaverse;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
//using log4net;
using System.Text;
using System.Text.Json;
using System.Text.RegularExpressions;
namespace OpenSim.Region.Framework.Scenes
{
public class LinksetData
{
public int m_MemoryLimit;
public int m_MemoryUsed;
private readonly object linksetDataLock = new();
public Dictionary<string, LinksetDataEntry> Data;
public LinksetData(int limit)
{
Data = new Dictionary<string, LinksetDataEntry>();
m_MemoryLimit = limit;
m_MemoryUsed = 0;
}
public LinksetData(int limit, int used)
{
Data = new Dictionary<string, LinksetDataEntry>();
m_MemoryLimit = limit;
m_MemoryUsed = used;
}
public LinksetData Copy()
{
lock (linksetDataLock)
{
var copy = new LinksetData(m_MemoryLimit, m_MemoryUsed);
foreach (var entry in Data)
{
LinksetDataEntry val = entry.Value.Copy();
copy.Data[entry.Key] = val;
}
return copy;
}
}
/// <summary>
/// Adds or updates a entry to linkset data
/// </summary>
/// <returns>
/// 0 if the data was successfully added or updated
/// 1 if the data could not be added or updated due to memory
/// 3 if the password did not match
/// 5 if the data is unchanged
/// </returns>
public int AddOrUpdate(string key, string value, string pass)
{
int deltaMem;
lock (linksetDataLock)
{
if (Data.TryGetValue(key, out LinksetDataEntry entry))
{
if (!entry.CheckPassword(pass))
return 3;
if (entry.Value == value)
return 5;
deltaMem = value.Length - entry.Value.Length;
if ((m_MemoryUsed + deltaMem) > m_MemoryLimit)
return 1;
m_MemoryUsed += deltaMem;
if(m_MemoryUsed < 0)
m_MemoryUsed = 0;
entry.Value = value;
return 0;
}
deltaMem = value.Length + key.Length;
if (!string.IsNullOrEmpty(pass))
deltaMem += pass.Length;
if ((m_MemoryUsed + deltaMem) > m_MemoryLimit)
return 1;
m_MemoryUsed += deltaMem;
Data[key] = new LinksetDataEntry()
{
Value = value,
Password = pass
};
return 0;
}
}
public int AddOrUpdate(string key, string value)
{
int deltaMem;
lock (linksetDataLock)
{
if (Data.TryGetValue(key, out LinksetDataEntry entry))
{
if (entry.IsProtected)
return 3;
if (entry.Value == value)
return 5;
deltaMem = value.Length - entry.Value.Length;
if ((m_MemoryUsed + deltaMem) > m_MemoryLimit)
return 1;
entry.Value = value;
m_MemoryUsed += deltaMem;
return 0;
}
deltaMem = value.Length + key.Length;
if ((m_MemoryUsed + deltaMem) > m_MemoryLimit)
return 1;
m_MemoryUsed += deltaMem;
Data[key] = new LinksetDataEntry()
{
Value = value,
Password = null
};
return 0;
}
}
/// <summary>
/// Deletes a named key from the key value store
/// </summary>
/// <param name="key">The key value we're removing</param>
/// <param name="pass">The password for a protected field (or string.Empty if not protected)</param>
/// <returns>
/// 0 if successful.
/// 1 if not due to the password.
/// -1 if no such key was found
/// </returns>
public int Remove(string key, string pass)
{
lock (linksetDataLock)
{
if (Data.Count <= 0)
return 4;
if (!Data.TryGetValue(key, out LinksetDataEntry entry))
return 4;
if (!entry.CheckPassword(pass))
return 3;
Data.Remove(key);
m_MemoryUsed -= key.Length + entry.Value.Length;
if (!string.IsNullOrEmpty(entry.Password))
m_MemoryUsed -= entry.Password.Length;
if (m_MemoryUsed < 0)
m_MemoryUsed = 0;
return 0;
}
}
public int Remove(string key)
{
lock (linksetDataLock)
{
if (Data.Count <= 0)
return 4;
if(string.IsNullOrEmpty(key))
return 4;
if (!Data.TryGetValue(key, out LinksetDataEntry entry))
return 4;
if (entry.IsProtected)
return 3;
Data.Remove(key);
m_MemoryUsed -= key.Length + entry.Value.Length;
if (m_MemoryUsed < 0)
m_MemoryUsed = 0;
return 0;
}
}
public string Get(string key, string pass)
{
lock (linksetDataLock)
{
return (Data.TryGetValue(key, out LinksetDataEntry entry) && entry.CheckPassword(pass)) ? entry.Value : string.Empty;
}
}
public string Get(string key)
{
lock (linksetDataLock)
{
return (Data.TryGetValue(key, out LinksetDataEntry entry) && entry.IsNotProtected) ? entry.Value : string.Empty;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool HasData()
{
return Data.Count > 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Count()
{
return Data.Count;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Free()
{
int free = m_MemoryLimit - m_MemoryUsed;
return free > 0 ? free : 0;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int Used()
{
return m_MemoryUsed;
}
public string[] RemoveByPattern(string pattern, string pass, out int notDeleted)
{
notDeleted = 0;
List<string> ret;
lock (linksetDataLock)
{
if (Data.Count <= 0)
return Array.Empty<string>();
try
{
ret = new List<string>();
Regex reg = new(pattern, RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(1));
foreach (var kvp in Data)
{
if (reg.IsMatch(kvp.Key))
{
if (kvp.Value.CheckPassword(pass))
{
int mem = kvp.Value.Value.Length + kvp.Key.Length;
if(kvp.Value.IsProtected)
mem += kvp.Value.Password.Length;
m_MemoryUsed -= mem;
ret.Add(kvp.Key);
}
else
notDeleted++;
}
}
}
catch
{
notDeleted = 0;
return Array.Empty<string>();
}
foreach (string k in ret)
Data.Remove(k);
if (m_MemoryUsed < 0)
m_MemoryUsed = 0;
return ret.ToArray();
}
}
public int CountByPattern(string pattern)
{
lock (linksetDataLock)
{
if (Data.Count <= 0)
return 0;
try
{
Regex reg = new(pattern, RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(1));
int ret = 0;
foreach (string k in Data.Keys)
{
if (reg.IsMatch(k))
ret++;
}
return ret;
}
catch
{
return 0;
}
}
}
public string[] ListKeysByPatttern(string pattern, int start, int count)
{
List<string> lkeys;
lock (linksetDataLock)
{
if (Data.Count <= 0 || start >= Data.Count)
return Array.Empty<string>();
try
{
Regex reg = new(pattern, RegexOptions.CultureInvariant, TimeSpan.FromMilliseconds(1));
lkeys = new(Data.Count);
foreach (string k in Data.Keys)
{
if (reg.IsMatch(k))
lkeys.Add(k);
}
}
catch
{
return Array.Empty<string>();
}
}
if (lkeys.Count == 0)
return Array.Empty<string>();
lkeys.Sort();
if (start < 0)
start = 0;
if (count < 1 || start + count > lkeys.Count)
count = lkeys.Count - start;
List<string> result = lkeys.GetRange(start, count);
return result.ToArray();
}
public string[] ListKeys(int start, int count)
{
string[] keys;
lock (linksetDataLock)
{
if (Data.Count <= 0 || start >= Data.Count)
return Array.Empty<string>();
keys = new string[Data.Count];
Data.Keys.CopyTo(keys, 0);
}
Array.Sort(keys);
if (start < 0)
start = 0;
if (count < 1)
return keys[start..];
int end = start + count;
if (end >= keys.Length)
return keys[start..];
return keys[start..end];
}
/// <summary>
/// Merge the linksetData present in another Linkset into this one.
/// The current root will have the new linkset for the merged sog.
/// If a key is present in our linksetData it wins, dont overide it.
/// </summary>
/// <param name="otherLinkset"></param>
public void MergeOther(LinksetData otherLinksetData)
{
if (otherLinksetData is null || otherLinksetData.Data is null || otherLinksetData.Count() == 0)
return;
lock (linksetDataLock)
{
if(m_MemoryUsed + otherLinksetData.Used() < m_MemoryLimit)
{
foreach (var kvp in otherLinksetData.Data)
{
if (Data.TryAdd(kvp.Key, kvp.Value))
{
m_MemoryUsed += kvp.Key.Length + kvp.Value.Value.Length;
if (!string.IsNullOrEmpty(kvp.Value.Password))
m_MemoryUsed += kvp.Value.Password.Length;
}
}
return;
}
SortedList<string,LinksetDataEntry> otherOrdered = new(otherLinksetData.Data);
foreach (var kvp in otherOrdered)
{
int mem = kvp.Key.Length + kvp.Value.Value.Length;
if (!string.IsNullOrEmpty(kvp.Value.Password))
mem += kvp.Value.Password.Length;
if (m_MemoryUsed + mem >= m_MemoryLimit)
return;
if (Data.TryAdd(kvp.Key, kvp.Value))
{
m_MemoryUsed += mem;
if (!string.IsNullOrEmpty(kvp.Value.Password))
m_MemoryUsed += kvp.Value.Password.Length;
}
}
otherLinksetData.Data = null;
otherLinksetData.m_MemoryUsed = 0;
}
}
/// <summary>
/// ResetLinksetData - clear the list and update the accounting.
/// </summary>
public void ResetLinksetData()
{
lock (linksetDataLock)
{
if (Data.Count <= 0)
return;
Data.Clear();
m_MemoryUsed = 0;
}
}
public string SerializeLinksetData()
{
lock (linksetDataLock)
{
return JsonSerializer.Serialize<Dictionary<string, LinksetDataEntry>>(Data);
}
}
}
public class LinksetDataEntry
{
public string Password;
public string Value;
public LinksetDataEntry() { }
public LinksetDataEntry(string value, string password)
{
Value = value;
Password = password;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool CheckPassword(string pass)
{
// A undocumented caveat for LinksetData appears to be that even for unprotected values,
// if a pass is provided, it is still treated as protected
return string.IsNullOrEmpty(Password) || (Password == pass);
}
public LinksetDataEntry Copy()
{
return new LinksetDataEntry
{
Password = Password,
Value = Value
};
}
public bool IsProtected
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return !string.IsNullOrEmpty(Password); }
}
public bool IsNotProtected
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get { return string.IsNullOrEmpty(Password); }
}
}
}