DocumentServer/ServerComponents/FileConverterUtils2/TaskQueueDB.cs
2015-04-28 19:22:25 +03:00

441 lines
17 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.Collections.Generic;
using System.Text;
using System.Xml;
using System.Configuration;
using System.Runtime.Serialization;
using System.Threading;
using System.Data;
using log4net;
namespace FileConverterUtils2
{
class CTaskQueueDataBase : ITaskQueue
{
private static readonly ILog _log = LogManager.GetLogger(typeof(CTaskQueueDataBase));
private string m_sConnectionString = ConfigurationManager.AppSettings["utils.taskqueue.db.connectionstring"];
private const string m_cstrTableName = "convert_queue";
private TimeSpan m_oRetentionPeriod;
private TimeSpan m_oVisibilityTimeout;
private delegate IDataReader ExecuteReader();
private delegate int ExecuteNonQuery();
private enum BusyType : int
{
not_busy = 0,
busy = 1
}
private delegate ErrorTypes DelegateRemoveTask(object key);
private delegate ErrorTypes DelegateAddTask(TaskQueueData oTask, Priority oPriority);
private class TransportClass : TransportClassAsyncOperation
{
public ExecuteReader m_delegateReader = null;
public ExecuteNonQuery m_delegateNonQuery = null;
public IDbConnection m_oSqlCon = null;
public IDbCommand m_oCommand = null;
public TaskQueueData m_oTaskQueueData = null;
public ErrorTypes m_eError = ErrorTypes.NoError;
public TransportClass(AsyncCallback fCallback, object oParam)
: base(fCallback, oParam)
{
}
public override void Close()
{
try
{
if (null != m_oCommand)
{
m_oCommand.Dispose();
m_oCommand = null;
}
if (null != m_oSqlCon)
{
m_oSqlCon.Close();
m_oSqlCon.Dispose();
m_oSqlCon = null;
}
}
catch
{
m_eError = ErrorTypes.TaskQueue;
}
}
public override void Dispose()
{
m_eError = ErrorTypes.TaskQueue;
try
{
if (null != m_oCommand)
{
m_oCommand.Dispose();
m_oCommand = null;
}
if (null != m_oSqlCon)
{
m_oSqlCon.Dispose();
m_oSqlCon = null;
}
}
catch
{
}
}
}
private TransportClass m_GetTask = null;
private DelegateRemoveTask m_RemoveTask = null;
private DelegateAddTask m_AddTask = null;
public CTaskQueueDataBase()
{
try
{
m_oVisibilityTimeout = TimeSpan.FromSeconds(double.Parse(ConfigurationManager.AppSettings["utils.taskqueue.db.visibility_timeout"] ?? "60"));
m_oRetentionPeriod = TimeSpan.FromSeconds(double.Parse(ConfigurationManager.AppSettings["utils.taskqueue.db.retention_period"] ?? "600"));
}
catch
{
}
}
public ErrorTypes AddTask(TaskQueueData oTask, Priority oPriority)
{
ErrorTypes eResult = ErrorTypes.TaskQueue;
try
{
oTask.VisibilityTimeout = m_oVisibilityTimeout;
string strId = (string)oTask.m_sKey;
string strInsertRow = GetInsertString(oTask, oPriority);
using (System.Data.IDbConnection dbConnection = GetDbConnection())
{
dbConnection.Open();
using (System.Data.IDbCommand oInsertCommand = dbConnection.CreateCommand())
{
oInsertCommand.CommandText = strInsertRow;
oInsertCommand.ExecuteNonQuery();
eResult = ErrorTypes.NoError;
}
}
}
catch
{
eResult = ErrorTypes.TaskQueue;
}
return eResult;
}
public void AddTaskBegin(TaskQueueData oTask, Priority oPriority, AsyncCallback fCallback, object oParam)
{
m_AddTask = AddTask;
m_AddTask.BeginInvoke(oTask, oPriority, fCallback, oParam);
}
public ErrorTypes AddTaskEnd(IAsyncResult ar)
{
ErrorTypes eRes = ErrorTypes.NoError;
try
{
eRes = m_AddTask.EndInvoke(ar);
}
catch
{
eRes = ErrorTypes.TaskQueue;
}
return eRes;
}
public TaskQueueData GetTask()
{
TaskQueueData oData = null;
try
{
using (System.Data.IDbConnection dbConnection = GetDbConnection())
{
dbConnection.Open();
using (IDbCommand oSelectCommand = dbConnection.CreateCommand())
{
oSelectCommand.CommandText = GetSelectString();
using (System.Data.IDataReader oDataReader = oSelectCommand.ExecuteReader())
{
while (true == oDataReader.Read())
{
uint ncq_id = Convert.ToUInt32(oDataReader["cq_id"]);
DateTime oTaskCreateTime = Convert.ToDateTime(oDataReader["cq_create_time"]);
if (DateTime.UtcNow < (oTaskCreateTime + m_oRetentionPeriod))
{
DateTime oTaskUpdateTime = Convert.ToDateTime(oDataReader["cq_update_time"]);
if (TryUpdateTask(ncq_id, oTaskUpdateTime))
{
oData = TaskQueueData.DeserializeFromXml(Convert.ToString(oDataReader["cq_data"]));
oData.m_oDataKey = ncq_id;
break;
}
}
else
{
RemoveTask(ncq_id);
}
}
}
}
}
}
catch
{
}
return oData;
}
private bool TryUpdateTask(uint ncq_id, DateTime oTaskUpdateTime)
{
bool bResult = false;
try
{
using (System.Data.IDbConnection dbConnection = GetDbConnection())
{
dbConnection.Open();
using (System.Data.IDbCommand oUpdateCommand = dbConnection.CreateCommand())
{
oUpdateCommand.CommandText = GetUpdateString(ncq_id, oTaskUpdateTime);
bResult = (oUpdateCommand.ExecuteNonQuery() > 0);
}
}
}
catch
{
}
return bResult;
}
public void GetTaskBegin(AsyncCallback fCallback, object oParam)
{
m_GetTask = new TransportClass(fCallback, oParam);
try
{
string strSelectSQL = GetSelectString();
m_GetTask.m_oSqlCon = GetDbConnection();
m_GetTask.m_oSqlCon.Open();
IDbCommand oSelCommand = m_GetTask.m_oSqlCon.CreateCommand();
oSelCommand.CommandText = strSelectSQL;
m_GetTask.m_oCommand = oSelCommand;
m_GetTask.m_delegateReader = new ExecuteReader(oSelCommand.ExecuteReader);
m_GetTask.m_delegateReader.BeginInvoke(GetTaskCallback, null);
}
catch(Exception e)
{
_log.Error("Exception cathed in GetTaskBegin:", e);
m_GetTask.DisposeAndCallback();
}
}
public TaskQueueData GetTaskEnd(IAsyncResult ar)
{
bool bResult = false;
if (ErrorTypes.NoError == m_GetTask.m_eError)
{
try
{
if (null != m_GetTask.m_delegateNonQuery)
{
if (m_GetTask.m_delegateNonQuery.EndInvoke(ar) > 0)
bResult = true;
else
bResult = false;
}
m_GetTask.Close();
}
catch(Exception e)
{
_log.Error("Exception cathed in GetTaskEnd:", e);
m_GetTask.Dispose();
}
}
return (bResult) ? m_GetTask.m_oTaskQueueData : null;
}
public ErrorTypes RemoveTask(object key)
{
ErrorTypes eResult = ErrorTypes.TaskQueue;
try
{
uint nId = (uint)key;
string strDeleteRow = GetDeleteString(nId);
using (System.Data.IDbConnection dbConnection = GetDbConnection())
{
dbConnection.Open();
using (IDbCommand oDelCommand = dbConnection.CreateCommand())
{
oDelCommand.CommandText = strDeleteRow;
oDelCommand.ExecuteNonQuery();
eResult = ErrorTypes.NoError;
}
}
}
catch
{
}
return eResult;
}
public void RemoveTaskBegin(object key, AsyncCallback fCallback, object oParam)
{
m_RemoveTask = RemoveTask;
m_RemoveTask.BeginInvoke(key, fCallback, oParam);
}
public ErrorTypes RemoveTaskEnd(IAsyncResult ar)
{
ErrorTypes eRes = ErrorTypes.NoError;
try
{
eRes = m_RemoveTask.EndInvoke(ar);
}
catch
{
eRes = ErrorTypes.TaskQueue;
}
return eRes;
}
private void GetTaskCallback(IAsyncResult ar)
{
try
{
uint ncq_id = 0;
DateTime oTaskUpdateTime = DateTime.UtcNow;
bool bIsExist = false;
using (IDataReader oReader = m_GetTask.m_delegateReader.EndInvoke(ar))
{
if (true == oReader.Read())
{
ncq_id = Convert.ToUInt32(oReader["cq_id"]);
oTaskUpdateTime = Convert.ToDateTime(oReader["cq_update_time"]);
m_GetTask.m_oTaskQueueData = TaskQueueData.DeserializeFromXml(Convert.ToString(oReader["cq_data"]));
m_GetTask.m_oTaskQueueData.m_oDataKey = ncq_id;
bIsExist = true;
}
}
if (null != m_GetTask.m_oCommand)
{
m_GetTask.m_oCommand.Dispose();
m_GetTask.m_oCommand = null;
}
m_GetTask.Close();
if (bIsExist)
{
IDbCommand oUpdateCommand = m_GetTask.m_oSqlCon.CreateCommand();
oUpdateCommand.CommandText = GetUpdateString(ncq_id, oTaskUpdateTime);
m_GetTask.m_oCommand = oUpdateCommand;
m_GetTask.m_delegateNonQuery = new ExecuteNonQuery(oUpdateCommand.ExecuteNonQuery);
m_GetTask.m_delegateNonQuery.BeginInvoke(m_GetTask.m_fCallback, m_GetTask.m_oParam);
}
else
{
m_GetTask.m_delegateNonQuery = null;
m_GetTask.FireCallback();
}
}
catch(Exception e)
{
_log.Error("Exception cathed in GetTaskCallback:", e);
m_GetTask.DisposeAndCallback();
}
}
private System.Data.IDbConnection GetDbConnection()
{
ConnectionStringSettings oConnectionSettings = ConfigurationManager.ConnectionStrings[m_sConnectionString];
System.Data.Common.DbProviderFactory dbProvider = System.Data.Common.DbProviderFactories.GetFactory(oConnectionSettings.ProviderName);
System.Data.IDbConnection newConnection = dbProvider.CreateConnection();
newConnection.ConnectionString = oConnectionSettings.ConnectionString;
return newConnection;
}
private string GetSelectString()
{
DateTime oMinPosibleStartHandleTime = DateTime.UtcNow.Subtract(m_oVisibilityTimeout);
return string.Format("SELECT * FROM {0} WHERE cq_isbusy <> '{1}' OR cq_update_time <= '{2}' ORDER BY cq_priority DESC;",
m_cstrTableName,
BusyType.busy.ToString("d"),
oMinPosibleStartHandleTime.ToString(Constants.mc_sDateTimeFormat));
}
private string GetInsertString(TaskQueueData oTask, Priority ePriority)
{
string sData = TaskQueueData.SerializeToXml(oTask);
return string.Format("INSERT INTO {0} " +
"(cq_data, cq_priority, cq_update_time, cq_create_time, cq_isbusy) " +
"VALUES ('{1}', '{2}', '{3}', '{3}', '{4}');",
m_cstrTableName,
Utils.MySqlEscape(sData, m_sConnectionString),
ePriority.ToString("d"),
DateTime.UtcNow.ToString(Constants.mc_sDateTimeFormat),
BusyType.not_busy.ToString("d"));
}
private string GetDeleteString(uint nId)
{
return "DELETE FROM " + m_cstrTableName + " WHERE cq_id='" + nId.ToString() + "'";
}
private string GetUpdateString(uint nCqId, DateTime oTaskUpdateTime)
{
return string.Format("UPDATE {0} SET cq_isbusy = '{1}', cq_update_time = '{2}' WHERE (cq_id = '{3}' AND cq_update_time = '{4}');",
m_cstrTableName,
BusyType.busy.ToString("d"),
DateTime.UtcNow.ToString(Constants.mc_sDateTimeFormat),
nCqId,
oTaskUpdateTime.ToString(Constants.mc_sDateTimeFormat));
}
}
}