519 lines
19 KiB
C#
519 lines
19 KiB
C#
/*
|
|
* (c) Copyright Ascensio System SIA 2010-2015
|
|
*
|
|
* This program is a free software product. You can redistribute it and/or
|
|
* modify it under the terms of the GNU Affero General Public License (AGPL)
|
|
* version 3 as published by the Free Software Foundation. In accordance with
|
|
* Section 7(a) of the GNU AGPL its Section 15 shall be amended to the effect
|
|
* that Ascensio System SIA expressly excludes the warranty of non-infringement
|
|
* of any third-party rights.
|
|
*
|
|
* This program is distributed WITHOUT ANY WARRANTY; without even the implied
|
|
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. For
|
|
* details, see the GNU AGPL at: http://www.gnu.org/licenses/agpl-3.0.html
|
|
*
|
|
* You can contact Ascensio System SIA at Lubanas st. 125a-25, Riga, Latvia,
|
|
* EU, LV-1021.
|
|
*
|
|
* The interactive user interfaces in modified source and object code versions
|
|
* of the Program must display Appropriate Legal Notices, as required under
|
|
* Section 5 of the GNU AGPL version 3.
|
|
*
|
|
* Pursuant to Section 7(b) of the License you must retain the original Product
|
|
* logo when distributing the program. Pursuant to Section 7(e) we decline to
|
|
* grant you any rights under trademark law for use of our trademarks.
|
|
*
|
|
* All the Product's GUI elements, including illustrations and icon sets, as
|
|
* well as technical writing content are licensed under the terms of the
|
|
* Creative Commons Attribution-ShareAlike 4.0 International. See the License
|
|
* terms at http://creativecommons.org/licenses/by-sa/4.0/legalcode
|
|
*
|
|
*/
|
|
using System;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Data;
|
|
using System.Configuration;
|
|
using System.Net;
|
|
using System.Xml.Serialization;
|
|
|
|
using ASC.Common.Data;
|
|
using ASC.Common.Data.Sql;
|
|
using ASC.Common.Data.Sql.Expressions;
|
|
|
|
using Enyim.Caching;
|
|
using Enyim.Caching.Configuration;
|
|
using Enyim.Caching.Memcached;
|
|
|
|
namespace FileConverterUtils2
|
|
{
|
|
class TaskResultCachedDB : ITaskResultInterface
|
|
{
|
|
private static System.Random m_oRandom = new System.Random();
|
|
private string m_sConnectionString = ConfigurationManager.AppSettings["utils.taskresult.db.connectionstring"];
|
|
private TimeSpan m_oTtl = TimeSpan.Parse(ConfigurationManager.AppSettings["utils.taskresult.cacheddb.ttl"] ?? "0.00:15:00");
|
|
|
|
private TaskResultDataBase m_oTaskResultDB = new TaskResultDataBase();
|
|
MemcachedClientConfiguration m_oMcConfig = null;
|
|
|
|
private delegate IDataReader ExecuteReader();
|
|
private delegate int ExecuteNonQuery();
|
|
private delegate ErrorTypes DelegateAdd(string sKey, TaskResultData oTast);
|
|
private delegate ErrorTypes DelegateUpdate(string sKey, TaskResultDataToUpdate oTast);
|
|
private delegate ErrorTypes DelegateGet(string sKey, out TaskResultData oTaskResultData);
|
|
private delegate ErrorTypes DelegateGetBegin(string sKey, AsyncCallback fCallback, object oParam);
|
|
private delegate ErrorTypes DelegateRemove(string sKey);
|
|
|
|
private delegate ErrorTypes DelegateAddToMC(string sKey, TaskResultData oTast);
|
|
|
|
private class TransportClass : TransportClassAsyncOperation
|
|
{
|
|
|
|
public ExecuteReader m_delegateReader = null;
|
|
public ExecuteNonQuery m_delegateNonQuery = null;
|
|
public DelegateGet m_delegateGet = null;
|
|
|
|
public TaskResultData m_oTast = null;
|
|
public ErrorTypes m_eError = ErrorTypes.NoError;
|
|
public bool m_bCreate = false;
|
|
public string m_sKey = null;
|
|
public bool m_bReadFromDB = false;
|
|
public TransportClass(AsyncCallback fCallback, object oParam)
|
|
: base(fCallback, oParam)
|
|
{
|
|
}
|
|
public override void Close()
|
|
{
|
|
|
|
}
|
|
public override void Dispose()
|
|
{
|
|
m_eError = ErrorTypes.TaskResult;
|
|
try
|
|
{
|
|
|
|
}
|
|
catch
|
|
{
|
|
}
|
|
}
|
|
}
|
|
private TransportClass m_oGetOrCreate = null;
|
|
|
|
private TransportClass m_oGet = null;
|
|
|
|
public TaskResultCachedDB()
|
|
{
|
|
InitMC();
|
|
}
|
|
private void InitMC()
|
|
{
|
|
if (null == m_oMcConfig)
|
|
{
|
|
m_oMcConfig = new MemcachedClientConfiguration();
|
|
|
|
string sServerName = ConfigurationManager.AppSettings["utils.taskresult.cacheddb.mc.server"] ?? "localhost:11211";
|
|
|
|
m_oMcConfig.AddServer(sServerName);
|
|
m_oMcConfig.Protocol = MemcachedProtocol.Text;
|
|
}
|
|
}
|
|
public ErrorTypes Add(string sKey, TaskResultData oTast)
|
|
{
|
|
AddToMC(sKey, oTast);
|
|
|
|
return m_oTaskResultDB.Add(sKey, oTast);
|
|
}
|
|
public void AddBegin(string sKey, TaskResultData oTast, AsyncCallback fCallback, object oParam)
|
|
{
|
|
DelegateAdd oDelegateAdd = new DelegateAdd(AddToMC);
|
|
|
|
oDelegateAdd.BeginInvoke(sKey, oTast, null, null);
|
|
|
|
m_oTaskResultDB.AddBegin(sKey, oTast, fCallback, oParam);
|
|
}
|
|
public ErrorTypes AddEnd(IAsyncResult ar)
|
|
{
|
|
return m_oTaskResultDB.AddEnd(ar);
|
|
}
|
|
public ErrorTypes AddRandomKey(string sKey, TaskResultData oTastToAdd, out TaskResultData oTastAdded)
|
|
{
|
|
return m_oTaskResultDB.AddRandomKey(sKey, oTastToAdd, out oTastAdded);
|
|
}
|
|
public void AddRandomKeyBegin(string sKey, TaskResultData oTastToAdd, AsyncCallback fCallback, object oParam)
|
|
{
|
|
|
|
m_oTaskResultDB.AddRandomKeyBegin(sKey, oTastToAdd, fCallback, oParam);
|
|
}
|
|
public ErrorTypes AddRandomKeyEnd(IAsyncResult ar, out TaskResultData oTast)
|
|
{
|
|
|
|
return m_oTaskResultDB.AddRandomKeyEnd(ar, out oTast);
|
|
}
|
|
public ErrorTypes Update(string sKey, TaskResultDataToUpdate oTast)
|
|
{
|
|
ErrorTypes oError = ErrorTypes.NoError;
|
|
bool bUpdate;
|
|
UpdateIfInMC(sKey, oTast, null, out bUpdate);
|
|
|
|
return oError;
|
|
}
|
|
public void UpdateBegin(string sKey, TaskResultDataToUpdate oTast, AsyncCallback fCallback, object oParam)
|
|
{
|
|
m_oTaskResultDB.UpdateBegin(sKey, oTast, fCallback, oParam);
|
|
|
|
}
|
|
public ErrorTypes UpdateEnd(IAsyncResult ar)
|
|
{
|
|
return m_oTaskResultDB.UpdateEnd(ar);
|
|
}
|
|
public ErrorTypes UpdateIf(string sKey, TaskResultDataToUpdate oMask, TaskResultDataToUpdate oTast, out bool bUpdate)
|
|
{
|
|
|
|
ErrorTypes oError = ErrorTypes.NoError;
|
|
|
|
UpdateIfInMC(sKey, oTast, oMask, out bUpdate);
|
|
|
|
return oError;
|
|
}
|
|
public void UpdateIfBegin(string sKey, TaskResultDataToUpdate oMask, TaskResultDataToUpdate oTast, AsyncCallback fCallback, object oParam)
|
|
{
|
|
m_oTaskResultDB.UpdateIfBegin(sKey, oMask, oTast, fCallback, oParam);
|
|
}
|
|
public ErrorTypes UpdateIfEnd(IAsyncResult ar, out bool bUpdate)
|
|
{
|
|
return m_oTaskResultDB.UpdateIfEnd(ar, out bUpdate);
|
|
}
|
|
public ErrorTypes Get(string sKey, out TaskResultData oTaskResultData)
|
|
{
|
|
oTaskResultData = null;
|
|
ErrorTypes oError = ErrorTypes.NoError;
|
|
try
|
|
{
|
|
GetFromMC(sKey, out oTaskResultData);
|
|
|
|
if (null == oTaskResultData)
|
|
{
|
|
oError = m_oTaskResultDB.Get(sKey, out oTaskResultData);
|
|
if (oError == ErrorTypes.NoError && oTaskResultData != null)
|
|
{
|
|
AddToMC(sKey, oTaskResultData);
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
oError = ErrorTypes.TaskResult;
|
|
}
|
|
|
|
return oError;
|
|
}
|
|
public void GetBegin(string sKey, AsyncCallback fCallback, object oParam)
|
|
{
|
|
m_oGet = new TransportClass(fCallback, oParam);
|
|
try
|
|
{
|
|
m_oGet.m_sKey = sKey;
|
|
m_oGet.m_delegateGet = new DelegateGet(GetFromMC);
|
|
m_oGet.m_delegateGet.BeginInvoke(sKey, out m_oGet.m_oTast, GetCallback, null);
|
|
}
|
|
catch
|
|
{
|
|
m_oGet.DisposeAndCallback();
|
|
}
|
|
}
|
|
public ErrorTypes GetEnd(IAsyncResult ar, out TaskResultData oTast)
|
|
{
|
|
oTast = null;
|
|
if (m_oGet.m_eError == ErrorTypes.NoError)
|
|
{
|
|
try
|
|
{
|
|
if (m_oGet.m_bReadFromDB)
|
|
{
|
|
m_oTaskResultDB.GetEnd(ar, out oTast);
|
|
DelegateAddToMC oDelegateAdd = new DelegateAddToMC(AddToMC);
|
|
oDelegateAdd.BeginInvoke(m_oGet.m_sKey, oTast, null, null);
|
|
}
|
|
else if (m_oGet.m_oTast != null)
|
|
oTast = m_oGet.m_oTast.Clone();
|
|
|
|
}
|
|
catch
|
|
{
|
|
m_oGet.m_eError = ErrorTypes.TaskResult;
|
|
}
|
|
}
|
|
return m_oGet.m_eError;
|
|
}
|
|
public ErrorTypes Get(string[] aKeys, out TaskResultData[] sTaskResults)
|
|
{
|
|
|
|
return m_oTaskResultDB.Get(aKeys, out sTaskResults);
|
|
}
|
|
public void GetBegin(string[] aKeys, AsyncCallback fCallback, object oParam)
|
|
{
|
|
m_oTaskResultDB.GetBegin(aKeys, fCallback, oParam);
|
|
}
|
|
public ErrorTypes GetEnd(IAsyncResult ar, out TaskResultData[] sTaskResults)
|
|
{
|
|
return m_oTaskResultDB.GetEnd(ar, out sTaskResults);
|
|
}
|
|
public ErrorTypes GetEditing(out TaskResultData[] oTast)
|
|
{
|
|
return m_oTaskResultDB.GetEditing(out oTast);
|
|
}
|
|
public void GetEditingBegin(AsyncCallback fCallback, object oParam)
|
|
{
|
|
m_oTaskResultDB.GetEditingBegin(fCallback, oParam);
|
|
}
|
|
public ErrorTypes GetEditingEnd(IAsyncResult ar, out TaskResultData[] oTast)
|
|
{
|
|
return m_oTaskResultDB.GetEditingEnd(ar, out oTast);
|
|
}
|
|
public ErrorTypes GetExpired(int nMaxCount, out List<TaskResultData> aTasts)
|
|
{
|
|
return m_oTaskResultDB.GetExpired(nMaxCount, out aTasts);
|
|
}
|
|
public ErrorTypes GetOrCreate(string sKey, TaskResultData oDefaultTast, out TaskResultData oTaskResultData, out bool bCreate)
|
|
{
|
|
return m_oTaskResultDB.GetOrCreate(sKey, oDefaultTast, out oTaskResultData, out bCreate);
|
|
}
|
|
public void GetOrCreateBegin(string sKey, TaskResultData oDataToAdd, AsyncCallback fCallback, object oParam)
|
|
{
|
|
m_oGetOrCreate = new TransportClass(fCallback, oParam);
|
|
m_oGetOrCreate.m_oTast = oDataToAdd;
|
|
m_oGetOrCreate.m_bCreate = true;
|
|
m_oGetOrCreate.m_sKey = sKey;
|
|
try
|
|
{
|
|
TaskResultData oTast = null;
|
|
m_oGetOrCreate.m_delegateGet = new DelegateGet(GetFromMC);
|
|
m_oGetOrCreate.m_delegateGet.BeginInvoke(sKey, out oTast, GetOrCreateCallback, null);
|
|
}
|
|
catch
|
|
{
|
|
m_oGetOrCreate.DisposeAndCallback();
|
|
}
|
|
}
|
|
public ErrorTypes GetOrCreateEnd(IAsyncResult ar, out TaskResultData oDataAdded, out bool bCreate)
|
|
{
|
|
bCreate = m_oGetOrCreate.m_bCreate;
|
|
oDataAdded = null;
|
|
if (ErrorTypes.NoError == m_oGetOrCreate.m_eError)
|
|
{
|
|
try
|
|
{
|
|
if (m_oGetOrCreate.m_bReadFromDB)
|
|
{
|
|
m_oTaskResultDB.GetOrCreateEnd(ar, out oDataAdded, out bCreate);
|
|
if (oDataAdded != null)
|
|
{
|
|
DelegateAddToMC oDelegateAddToMC = new DelegateAddToMC(AddToMC);
|
|
oDelegateAddToMC.BeginInvoke(m_oGetOrCreate.m_sKey, oDataAdded, null, null);
|
|
}
|
|
}
|
|
else if (null != m_oGetOrCreate.m_oTast)
|
|
oDataAdded = m_oGetOrCreate.m_oTast.Clone();
|
|
}
|
|
catch
|
|
{
|
|
m_oGetOrCreate.Dispose();
|
|
}
|
|
}
|
|
return m_oGetOrCreate.m_eError;
|
|
}
|
|
public ErrorTypes Remove(string sKey)
|
|
{
|
|
RemoveFromMC(sKey);
|
|
return m_oTaskResultDB.Remove(sKey);
|
|
}
|
|
public void RemoveBegin(string sKey, AsyncCallback fCallback, object oParam)
|
|
{
|
|
DelegateRemove oDelegateRemove = new DelegateRemove(RemoveFromMC);
|
|
oDelegateRemove.BeginInvoke(sKey, null, null);
|
|
m_oTaskResultDB.RemoveBegin(sKey, fCallback, oParam);
|
|
}
|
|
public ErrorTypes RemoveEnd(IAsyncResult ar)
|
|
{
|
|
ErrorTypes eErrorTypes = ErrorTypes.NoError;
|
|
try
|
|
{
|
|
eErrorTypes = m_oTaskResultDB.RemoveEnd(ar);
|
|
}
|
|
catch
|
|
{
|
|
eErrorTypes = ErrorTypes.TaskResult;
|
|
}
|
|
return eErrorTypes;
|
|
}
|
|
private ErrorTypes AddToMC(string sKey, TaskResultData oTast)
|
|
{
|
|
return AddToMCWithCas(sKey, oTast, 0);
|
|
}
|
|
private ErrorTypes AddToMCWithCas(string sKey, TaskResultData oTast, ulong cas)
|
|
{
|
|
ErrorTypes oError = ErrorTypes.NoError;
|
|
try
|
|
{
|
|
using (MemcachedClient oMc = new MemcachedClient(m_oMcConfig))
|
|
{
|
|
string sDataToStore = null;
|
|
|
|
XmlSerializer oXmlSerializer = new XmlSerializer(typeof(TaskResultData));
|
|
using (StringWriter oStringWriter = new StringWriter())
|
|
{
|
|
oXmlSerializer.Serialize(oStringWriter, oTast);
|
|
sDataToStore = oStringWriter.ToString();
|
|
}
|
|
|
|
if (cas != 0)
|
|
oMc.Cas(StoreMode.Set, sKey, sDataToStore, m_oTtl, cas);
|
|
else
|
|
oMc.Store(StoreMode.Set, sKey, sDataToStore, m_oTtl);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
oError = ErrorTypes.TaskResult;
|
|
}
|
|
|
|
return oError;
|
|
}
|
|
private ErrorTypes GetFromMC(string sKey, out TaskResultData oTast)
|
|
{
|
|
ulong cas = 0;
|
|
return GetFromMCWithCas(sKey, out oTast, out cas);
|
|
}
|
|
private ErrorTypes GetFromMCWithCas(string sKey, out TaskResultData oTast, out ulong cas)
|
|
{
|
|
ErrorTypes oError = ErrorTypes.NoError;
|
|
oTast = null;
|
|
cas = 0;
|
|
try
|
|
{
|
|
using (MemcachedClient oMc = new MemcachedClient(m_oMcConfig))
|
|
{
|
|
CasResult<string> oGetData = oMc.GetWithCas<string>(sKey);
|
|
|
|
if (oGetData.Result != null)
|
|
{
|
|
cas = oGetData.Cas;
|
|
|
|
XmlSerializer oXmlSerializer = new XmlSerializer(typeof(TaskResultData));
|
|
using (StringReader oStringReader = new StringReader(oGetData.Result))
|
|
{
|
|
oTast = (TaskResultData)oXmlSerializer.Deserialize(oStringReader);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
oError = ErrorTypes.TaskResult;
|
|
}
|
|
|
|
return oError;
|
|
}
|
|
private ErrorTypes UpdateIfInMC(string sKey, TaskResultDataToUpdate oTast, TaskResultDataToUpdate oMask, out bool bUpdate)
|
|
{
|
|
ErrorTypes oError = ErrorTypes.NoError;
|
|
bUpdate = false;
|
|
try
|
|
{
|
|
TaskResultData oTask = null;
|
|
ulong cas = 0;
|
|
GetFromMCWithCas(sKey, out oTask, out cas);
|
|
|
|
if (oTask == null)
|
|
m_oTaskResultDB.Get(sKey, out oTask);
|
|
|
|
if (oTask != null && oTask.eStatus != FileStatus.Ok && oTask.IsValidMask(oMask))
|
|
{
|
|
bUpdate = true;
|
|
oTask.Update(oTast);
|
|
|
|
AddToMCWithCas(sKey, oTask, cas);
|
|
|
|
if (oTask.eStatus != FileStatus.Convert)
|
|
oError = m_oTaskResultDB.Update(sKey, oTast);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
oError = ErrorTypes.TaskResult;
|
|
}
|
|
|
|
return oError;
|
|
}
|
|
private ErrorTypes RemoveFromMC(string sKey)
|
|
{
|
|
ErrorTypes oError = ErrorTypes.NoError;
|
|
try
|
|
{
|
|
using (MemcachedClient oMc = new MemcachedClient(m_oMcConfig))
|
|
{
|
|
oMc.Remove(sKey);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
oError = ErrorTypes.TaskResult;
|
|
}
|
|
return oError;
|
|
}
|
|
private void GetCallback(IAsyncResult ar)
|
|
{
|
|
try
|
|
{
|
|
TaskResultData oTast = null;
|
|
m_oGet.m_eError = m_oGet.m_delegateGet.EndInvoke(out oTast, ar);
|
|
m_oGet.m_delegateGet = null;
|
|
|
|
if (oTast != null)
|
|
{
|
|
m_oGet.m_sKey = null;
|
|
m_oGet.m_oTast = oTast;
|
|
m_oGet.FireCallback();
|
|
}
|
|
else
|
|
{
|
|
m_oGet.m_bReadFromDB = true;
|
|
m_oTaskResultDB.GetBegin(m_oGet.m_sKey, m_oGet.m_fCallback, m_oGet.m_oParam);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
m_oGet.DisposeAndCallback();
|
|
}
|
|
}
|
|
private void GetOrCreateCallback(IAsyncResult ar)
|
|
{
|
|
try
|
|
{
|
|
TaskResultData oTaskResult = null;
|
|
m_oGetOrCreate.m_delegateGet.EndInvoke(out oTaskResult, ar);
|
|
m_oGetOrCreate.m_delegateGet = null;
|
|
|
|
if (oTaskResult != null)
|
|
{
|
|
m_oGetOrCreate.m_bCreate = false;
|
|
m_oGetOrCreate.m_oTast = oTaskResult;
|
|
m_oGetOrCreate.FireCallback();
|
|
}
|
|
else
|
|
{
|
|
m_oGetOrCreate.m_bReadFromDB = true;
|
|
m_oTaskResultDB.GetOrCreateBegin(m_oGetOrCreate.m_sKey, m_oGetOrCreate.m_oTast, m_oGetOrCreate.m_fCallback, m_oGetOrCreate.m_oParam);
|
|
}
|
|
}
|
|
catch
|
|
{
|
|
m_oGetOrCreate.DisposeAndCallback();
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|