update db connections
This commit is contained in:
parent
71854c1a09
commit
81d685b882
|
@ -387,6 +387,7 @@ namespace Emby.Common.Implementations.ScheduledTasks
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_currentTask = null;
|
_currentTask = null;
|
||||||
|
GC.Collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Model.Logging;
|
using MediaBrowser.Model.Logging;
|
||||||
|
@ -43,6 +44,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
//CheckOk(rc);
|
//CheckOk(rc);
|
||||||
|
|
||||||
rc = raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD, 1);
|
rc = raw.sqlite3_config(raw.SQLITE_CONFIG_MULTITHREAD, 1);
|
||||||
|
//rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SINGLETHREAD, 1);
|
||||||
//rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SERIALIZED, 1);
|
//rc = raw.sqlite3_config(raw.SQLITE_CONFIG_SERIALIZED, 1);
|
||||||
//CheckOk(rc);
|
//CheckOk(rc);
|
||||||
|
|
||||||
|
@ -54,9 +56,20 @@ namespace Emby.Server.Implementations.Data
|
||||||
private static bool _versionLogged;
|
private static bool _versionLogged;
|
||||||
|
|
||||||
private string _defaultWal;
|
private string _defaultWal;
|
||||||
|
protected ManagedConnection _connection;
|
||||||
|
|
||||||
protected SQLiteDatabaseConnection CreateConnection(bool isReadOnly = false)
|
protected virtual bool EnableSingleConnection
|
||||||
{
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ManagedConnection CreateConnection(bool isReadOnly = false)
|
||||||
|
{
|
||||||
|
if (_connection != null)
|
||||||
|
{
|
||||||
|
return _connection;
|
||||||
|
}
|
||||||
|
|
||||||
lock (WriteLock)
|
lock (WriteLock)
|
||||||
{
|
{
|
||||||
if (!_versionLogged)
|
if (!_versionLogged)
|
||||||
|
@ -82,7 +95,15 @@ namespace Emby.Server.Implementations.Data
|
||||||
connectionFlags |= ConnectionFlags.ReadWrite;
|
connectionFlags |= ConnectionFlags.ReadWrite;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (EnableSingleConnection)
|
||||||
|
{
|
||||||
|
connectionFlags |= ConnectionFlags.PrivateCache;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
connectionFlags |= ConnectionFlags.SharedCached;
|
connectionFlags |= ConnectionFlags.SharedCached;
|
||||||
|
}
|
||||||
|
|
||||||
connectionFlags |= ConnectionFlags.NoMutex;
|
connectionFlags |= ConnectionFlags.NoMutex;
|
||||||
|
|
||||||
var db = SQLite3.Open(DbFilePath, connectionFlags, null);
|
var db = SQLite3.Open(DbFilePath, connectionFlags, null);
|
||||||
|
@ -101,6 +122,11 @@ namespace Emby.Server.Implementations.Data
|
||||||
"PRAGMA synchronous=Normal"
|
"PRAGMA synchronous=Normal"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (CacheSize.HasValue)
|
||||||
|
{
|
||||||
|
queries.Add("PRAGMA cache_size=-" + CacheSize.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
}
|
||||||
|
|
||||||
if (EnableTempStoreMemory)
|
if (EnableTempStoreMemory)
|
||||||
{
|
{
|
||||||
queries.Add("PRAGMA temp_store = memory");
|
queries.Add("PRAGMA temp_store = memory");
|
||||||
|
@ -135,10 +161,22 @@ namespace Emby.Server.Implementations.Data
|
||||||
db.Execute(query);
|
db.Execute(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
return db;
|
_connection = new ManagedConnection(db, false);
|
||||||
|
|
||||||
|
return _connection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IStatement PrepareStatement(ManagedConnection connection, string sql)
|
||||||
|
{
|
||||||
|
return connection.PrepareStatement(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IStatement PrepareStatementSafe(ManagedConnection connection, string sql)
|
||||||
|
{
|
||||||
|
return connection.PrepareStatement(sql);
|
||||||
|
}
|
||||||
|
|
||||||
public IStatement PrepareStatement(IDatabaseConnection connection, string sql)
|
public IStatement PrepareStatement(IDatabaseConnection connection, string sql)
|
||||||
{
|
{
|
||||||
return connection.PrepareStatement(sql);
|
return connection.PrepareStatement(sql);
|
||||||
|
@ -159,7 +197,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
return sql.Select(connection.PrepareStatement).ToList();
|
return sql.Select(connection.PrepareStatement).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void RunDefaultInitialization(IDatabaseConnection db)
|
protected void RunDefaultInitialization(ManagedConnection db)
|
||||||
{
|
{
|
||||||
var queries = new List<string>
|
var queries = new List<string>
|
||||||
{
|
{
|
||||||
|
@ -246,6 +284,12 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
using (WriteLock.Write())
|
using (WriteLock.Write())
|
||||||
{
|
{
|
||||||
|
if (_connection != null)
|
||||||
|
{
|
||||||
|
_connection.Close();
|
||||||
|
_connection = null;
|
||||||
|
}
|
||||||
|
|
||||||
CloseConnection();
|
CloseConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -340,7 +384,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
//{
|
//{
|
||||||
// return new DummyToken();
|
// return new DummyToken();
|
||||||
//}
|
//}
|
||||||
return new ReadLockToken(obj);
|
return new WriteLockToken(obj);
|
||||||
}
|
}
|
||||||
public static IDisposable Write(this ReaderWriterLockSlim obj)
|
public static IDisposable Write(this ReaderWriterLockSlim obj)
|
||||||
{
|
{
|
||||||
|
|
|
@ -129,7 +129,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Attach(IDatabaseConnection db, string path, string alias)
|
public static void Attach(ManagedConnection db, string path, string alias)
|
||||||
{
|
{
|
||||||
var commandText = string.Format("attach @path as {0};", alias);
|
var commandText = string.Format("attach @path as {0};", alias);
|
||||||
|
|
||||||
|
|
|
@ -105,13 +105,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
var cacheSize = _config.Configuration.SqliteCacheSize;
|
return 20000;
|
||||||
if (cacheSize <= 0)
|
|
||||||
{
|
|
||||||
cacheSize = Math.Min(Environment.ProcessorCount * 50000, 100000);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0 - cacheSize;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,9 +370,9 @@ namespace Emby.Server.Implementations.Data
|
||||||
//await Vacuum(_connection).ConfigureAwait(false);
|
//await Vacuum(_connection).ConfigureAwait(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
userDataRepo.Initialize(WriteLock);
|
userDataRepo.Initialize(WriteLock, _connection);
|
||||||
|
|
||||||
_shrinkMemoryTimer = _timerFactory.Create(OnShrinkMemoryTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(30));
|
_shrinkMemoryTimer = _timerFactory.Create(OnShrinkMemoryTimerCallback, null, TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(15));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnShrinkMemoryTimerCallback(object state)
|
private void OnShrinkMemoryTimerCallback(object state)
|
||||||
|
@ -1258,9 +1252,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
{
|
||||||
return connection.RunInTransaction(db =>
|
using (var statement = PrepareStatementSafe(connection, "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid"))
|
||||||
{
|
|
||||||
using (var statement = PrepareStatementSafe(db, "select " + string.Join(",", _retriveItemColumns) + " from TypedBaseItems where guid = @guid"))
|
|
||||||
{
|
{
|
||||||
statement.TryBind("@guid", id);
|
statement.TryBind("@guid", id);
|
||||||
|
|
||||||
|
@ -1271,8 +1263,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2090,12 +2080,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
using (WriteLock.Read())
|
using (WriteLock.Read())
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
|
||||||
return connection.RunInTransaction(db =>
|
|
||||||
{
|
{
|
||||||
var list = new List<ChapterInfo>();
|
var list = new List<ChapterInfo>();
|
||||||
|
|
||||||
using (var statement = PrepareStatementSafe(db, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"))
|
using (var statement = PrepareStatementSafe(connection, "select StartPositionTicks,Name,ImagePath,ImageDateModified from " + ChaptersTableName + " where ItemId = @ItemId order by ChapterIndex asc"))
|
||||||
{
|
{
|
||||||
statement.TryBind("@ItemId", id);
|
statement.TryBind("@ItemId", id);
|
||||||
|
|
||||||
|
@ -2106,8 +2094,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2486,9 +2472,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
{
|
||||||
return connection.RunInTransaction(db =>
|
using (var statement = PrepareStatementSafe(connection, commandText))
|
||||||
{
|
|
||||||
using (var statement = PrepareStatementSafe(db, commandText))
|
|
||||||
{
|
{
|
||||||
if (EnableJoinUserData(query))
|
if (EnableJoinUserData(query))
|
||||||
{
|
{
|
||||||
|
@ -2504,8 +2488,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
LogQueryTime("GetCount", commandText, now);
|
LogQueryTime("GetCount", commandText, now);
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2982,12 +2964,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
using (WriteLock.Read())
|
using (WriteLock.Read())
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
|
||||||
return connection.RunInTransaction(db =>
|
|
||||||
{
|
{
|
||||||
var list = new List<Guid>();
|
var list = new List<Guid>();
|
||||||
|
|
||||||
using (var statement = PrepareStatementSafe(db, commandText))
|
using (var statement = PrepareStatementSafe(connection, commandText))
|
||||||
{
|
{
|
||||||
if (EnableJoinUserData(query))
|
if (EnableJoinUserData(query))
|
||||||
{
|
{
|
||||||
|
@ -3008,8 +2988,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
LogQueryTime("GetItemList", commandText, now);
|
LogQueryTime("GetItemList", commandText, now);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4677,11 +4655,9 @@ namespace Emby.Server.Implementations.Data
|
||||||
using (WriteLock.Read())
|
using (WriteLock.Read())
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
|
||||||
return connection.RunInTransaction(db =>
|
|
||||||
{
|
{
|
||||||
var list = new List<string>();
|
var list = new List<string>();
|
||||||
using (var statement = PrepareStatementSafe(db, commandText))
|
using (var statement = PrepareStatementSafe(connection, commandText))
|
||||||
{
|
{
|
||||||
// Run this again to bind the params
|
// Run this again to bind the params
|
||||||
GetPeopleWhereClauses(query, statement);
|
GetPeopleWhereClauses(query, statement);
|
||||||
|
@ -4692,7 +4668,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4720,12 +4695,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
using (WriteLock.Read())
|
using (WriteLock.Read())
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
|
||||||
return connection.RunInTransaction(db =>
|
|
||||||
{
|
{
|
||||||
var list = new List<PersonInfo>();
|
var list = new List<PersonInfo>();
|
||||||
|
|
||||||
using (var statement = PrepareStatementSafe(db, commandText))
|
using (var statement = PrepareStatementSafe(connection, commandText))
|
||||||
{
|
{
|
||||||
// Run this again to bind the params
|
// Run this again to bind the params
|
||||||
GetPeopleWhereClauses(query, statement);
|
GetPeopleWhereClauses(query, statement);
|
||||||
|
@ -4737,7 +4710,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4938,12 +4910,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
using (WriteLock.Read())
|
using (WriteLock.Read())
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
|
||||||
return connection.RunInTransaction(db =>
|
|
||||||
{
|
{
|
||||||
var list = new List<string>();
|
var list = new List<string>();
|
||||||
|
|
||||||
using (var statement = PrepareStatementSafe(db, commandText))
|
using (var statement = PrepareStatementSafe(connection, commandText))
|
||||||
{
|
{
|
||||||
foreach (var row in statement.ExecuteQuery())
|
foreach (var row in statement.ExecuteQuery())
|
||||||
{
|
{
|
||||||
|
@ -4957,7 +4927,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
LogQueryTime("GetItemValueNames", commandText, now);
|
LogQueryTime("GetItemValueNames", commandText, now);
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5433,12 +5402,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
using (WriteLock.Read())
|
using (WriteLock.Read())
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
|
||||||
return connection.RunInTransaction(db =>
|
|
||||||
{
|
{
|
||||||
var list = new List<MediaStream>();
|
var list = new List<MediaStream>();
|
||||||
|
|
||||||
using (var statement = PrepareStatementSafe(db, cmdText))
|
using (var statement = PrepareStatementSafe(connection, cmdText))
|
||||||
{
|
{
|
||||||
statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
|
statement.TryBind("@ItemId", query.ItemId.ToGuidParamValue());
|
||||||
|
|
||||||
|
@ -5459,8 +5426,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
|
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,8 +42,10 @@ namespace Emby.Server.Implementations.Data
|
||||||
/// Opens the connection to the database
|
/// Opens the connection to the database
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>Task.</returns>
|
/// <returns>Task.</returns>
|
||||||
public void Initialize(ReaderWriterLockSlim writeLock)
|
public void Initialize(ReaderWriterLockSlim writeLock, ManagedConnection managedConnection)
|
||||||
{
|
{
|
||||||
|
_connection = managedConnection;
|
||||||
|
|
||||||
WriteLock.Dispose();
|
WriteLock.Dispose();
|
||||||
WriteLock = writeLock;
|
WriteLock = writeLock;
|
||||||
|
|
||||||
|
@ -90,7 +92,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ImportUserDataIfNeeded(IDatabaseConnection connection)
|
private void ImportUserDataIfNeeded(ManagedConnection connection)
|
||||||
{
|
{
|
||||||
if (!_fileSystem.FileExists(_importFile))
|
if (!_fileSystem.FileExists(_importFile))
|
||||||
{
|
{
|
||||||
|
@ -117,7 +119,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
}, TransactionMode);
|
}, TransactionMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ImportUserData(IDatabaseConnection connection, string file)
|
private void ImportUserData(ManagedConnection connection, string file)
|
||||||
{
|
{
|
||||||
SqliteExtensions.Attach(connection, file, "UserDataBackup");
|
SqliteExtensions.Attach(connection, file, "UserDataBackup");
|
||||||
|
|
||||||
|
@ -300,9 +302,7 @@ namespace Emby.Server.Implementations.Data
|
||||||
{
|
{
|
||||||
using (var connection = CreateConnection(true))
|
using (var connection = CreateConnection(true))
|
||||||
{
|
{
|
||||||
return connection.RunInTransaction(db =>
|
using (var statement = connection.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId"))
|
||||||
{
|
|
||||||
using (var statement = db.PrepareStatement("select key,userid,rating,played,playCount,isFavorite,playbackPositionTicks,lastPlayedDate,AudioStreamIndex,SubtitleStreamIndex from userdata where key =@Key and userId=@UserId"))
|
|
||||||
{
|
{
|
||||||
statement.TryBind("@UserId", userId.ToGuidParamValue());
|
statement.TryBind("@UserId", userId.ToGuidParamValue());
|
||||||
statement.TryBind("@Key", key);
|
statement.TryBind("@Key", key);
|
||||||
|
@ -314,8 +314,6 @@ namespace Emby.Server.Implementations.Data
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
}, ReadTransactionMode);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@
|
||||||
<Compile Include="Connect\ConnectManager.cs" />
|
<Compile Include="Connect\ConnectManager.cs" />
|
||||||
<Compile Include="Connect\Responses.cs" />
|
<Compile Include="Connect\Responses.cs" />
|
||||||
<Compile Include="Connect\Validator.cs" />
|
<Compile Include="Connect\Validator.cs" />
|
||||||
|
<Compile Include="Data\ManagedConnection.cs" />
|
||||||
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
|
<Compile Include="Data\SqliteDisplayPreferencesRepository.cs" />
|
||||||
<Compile Include="Data\SqliteFileOrganizationRepository.cs" />
|
<Compile Include="Data\SqliteFileOrganizationRepository.cs" />
|
||||||
<Compile Include="Data\SqliteItemRepository.cs" />
|
<Compile Include="Data\SqliteItemRepository.cs" />
|
||||||
|
|
|
@ -191,7 +191,6 @@ namespace MediaBrowser.Model.Configuration
|
||||||
public int SharingExpirationDays { get; set; }
|
public int SharingExpirationDays { get; set; }
|
||||||
|
|
||||||
public int SchemaVersion { get; set; }
|
public int SchemaVersion { get; set; }
|
||||||
public int SqliteCacheSize { get; set; }
|
|
||||||
|
|
||||||
public bool EnableAnonymousUsageReporting { get; set; }
|
public bool EnableAnonymousUsageReporting { get; set; }
|
||||||
public bool EnableStandaloneMusicKeys { get; set; }
|
public bool EnableStandaloneMusicKeys { get; set; }
|
||||||
|
@ -214,7 +213,6 @@ namespace MediaBrowser.Model.Configuration
|
||||||
{
|
{
|
||||||
LocalNetworkAddresses = new string[] { };
|
LocalNetworkAddresses = new string[] { };
|
||||||
CodecsUsed = new string[] { };
|
CodecsUsed = new string[] { };
|
||||||
SqliteCacheSize = 0;
|
|
||||||
ImageExtractionTimeoutMs = 0;
|
ImageExtractionTimeoutMs = 0;
|
||||||
|
|
||||||
EnableLocalizedGuids = true;
|
EnableLocalizedGuids = true;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user