Add initial ThreadSafeCache class, also do Database.TableExists checks for zones/portals/messages.

This commit is contained in:
UnknownShadow200 2016-07-28 22:07:14 +10:00
parent b5b8197c04
commit cb51be2d6a
7 changed files with 109 additions and 21 deletions

View File

@ -351,8 +351,7 @@ namespace MCGalaxy {
try {
Level level = LvlFile.Load(name, path);
level.setPhysics(phys);
level.backedup = true;
LevelDB.LoadZones(level, name);
level.backedup = true;
level.jailx = (ushort)(level.spawnx * 32);
level.jaily = (ushort)(level.spawny * 32);
@ -360,13 +359,7 @@ namespace MCGalaxy {
level.jailrotx = level.rotx;
level.jailroty = level.roty;
level.StartPhysics();
try {
LevelDB.LoadMetadata(level, name);
} catch (Exception e) {
Server.ErrorLog(e);
}
try {
string propsPath = LevelInfo.FindPropertiesFile(level.name);
if (propsPath != null)
@ -385,6 +378,12 @@ namespace MCGalaxy {
level.CustomBlockDefs[i] = defs[i];
}
Bots.BotsFile.LoadBots(level);
object locker = ThreadSafeCache.DBCache.Get(name);
lock (locker) {
LevelDB.LoadZones(level, name);
LevelDB.LoadMetadata(level, name);
}
Server.s.Log(string.Format("Level \"{0}\" loaded.", level.name));
if (LevelLoaded != null)

View File

@ -109,6 +109,7 @@ namespace MCGalaxy {
}
internal static void LoadZones(Level level, string name) {
if (!Database.TableExists("Zone" + name)) return;
using (DataTable table = Database.Fill("SELECT * FROM `Zone" + name + "`")) {
Level.Zone Zn;
foreach (DataRow row in table.Rows) {
@ -124,7 +125,8 @@ namespace MCGalaxy {
}
}
internal static void LoadMetadata(Level level, string name) {
internal static void LoadPortals(Level level, string name) {
if (!Database.TableExists("Portals" + name)) return;
using (DataTable table = Database.Fill("SELECT * FROM `Portals" + name + "`")) {
foreach (DataRow row in table.Rows) {
byte tile = level.GetTile(ushort.Parse(row["EntryX"].ToString()),
@ -136,7 +138,10 @@ namespace MCGalaxy {
row["EntryX"], row["EntryY"], row["EntryZ"]);
}
}
}
internal static void LoadMessages(Level level, string name) {
if (!Database.TableExists("Messages" + name)) return;
using (DataTable table = Database.Fill("SELECT * FROM `Messages" + name + "`")) {
foreach (DataRow row in table.Rows) {
byte tile = level.GetTile(ushort.Parse(row["X"].ToString()),
@ -159,12 +164,12 @@ namespace MCGalaxy {
public static void CreateZone(string level, Level.Zone zn) {
Database.Execute("INSERT INTO `Zone" + level + "` (Owner, SmallX, SmallY, " +
"SmallZ, BigX, BigY, BigZ) VALUES (@0, @1, @2, @3, @4, @5, @6)",
"SmallZ, BigX, BigY, BigZ) VALUES (@0, @1, @2, @3, @4, @5, @6)",
zn.Owner, zn.smallX, zn.smallY, zn.smallZ, zn.bigX, zn.bigY, zn.bigZ);
}
const string createBlock =
internal const string createBlock =
@"CREATE TABLE if not exists `Block{0}` (
Username CHAR(20),
TimePerformed DATETIME,
@ -174,7 +179,7 @@ Z SMALLINT UNSIGNED,
Type TINYINT UNSIGNED,
Deleted {1})";
const string createPortals =
internal const string createPortals =
@"CREATE TABLE if not exists `Portals{0}` (
EntryX SMALLINT UNSIGNED,
EntryY SMALLINT UNSIGNED,
@ -184,14 +189,14 @@ ExitX SMALLINT UNSIGNED,
ExitY SMALLINT UNSIGNED,
ExitZ SMALLINT UNSIGNED)";
const string createMessages =
internal const string createMessages =
@"CREATE TABLE if not exists `Messages{0}` (
X SMALLINT UNSIGNED,
Y SMALLINT UNSIGNED,
Z SMALLINT UNSIGNED,
Message CHAR(255))";
const string createZones =
internal const string createZones =
@"CREATE TABLE if not exists `Zone{0}` (
SmallX SMALLINT UNSIGNED,
SmallY SMALLINT UNSIGNED,

View File

@ -580,6 +580,7 @@
<Compile Include="Server\Server.Fields.cs" />
<Compile Include="Server\Server.Init.cs" />
<Compile Include="Server\Server.Tasks.cs" />
<Compile Include="Server\ThreadSafeCache.cs" />
<Compile Include="Server\Updater.cs" />
<Compile Include="API\WebServer.cs" />
<Compile Include="util\BufferedBlockSender.cs" />

View File

@ -115,11 +115,14 @@ namespace MCGalaxy {
Mods.Clear();
Background.QueueOnce(UpdateStaffListTask);
MainScheduler.QueueRepeat(TemprankExpiryTask, null, TimeSpan.FromSeconds(60));
MainScheduler.QueueRepeat(TemprankExpiryTask, null,
TimeSpan.FromMinutes(1));
Background.QueueRepeat(AutoSaveTask, 1,
TimeSpan.FromSeconds(Server.backupInterval));
TimeSpan.FromSeconds(Server.backupInterval));
Background.QueueRepeat(BlockUpdatesTask, null,
TimeSpan.FromSeconds(Server.blockInterval));
TimeSpan.FromSeconds(Server.blockInterval));
Background.QueueRepeat(ThreadSafeCache.CleanupTask, null,
TimeSpan.FromMinutes(5));
}
void EnsureFilesExist() {

81
Server/ThreadSafeCache.cs Normal file
View File

@ -0,0 +1,81 @@
/*
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may
not use this file except in compliance with the Licenses. You may
obtain a copy of the Licenses at
http://www.opensource.org/licenses/ecl2.php
http://www.gnu.org/licenses/gpl-3.0.html
Unless required by applicable law or agreed to in writing,
software distributed under the Licenses are distributed on an "AS IS"
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
or implied. See the Licenses for the specific language governing
permissions and limitations under the Licenses.
*/
using System;
using System.Collections.Generic;
namespace MCGalaxy {
public sealed class ThreadSafeCache {
static readonly List<ThreadSafeCache> caches = new List<ThreadSafeCache>();
static readonly object cachesLock = new object();
public static ThreadSafeCache DBCache = new ThreadSafeCache(() => new object());
readonly object locker = new object();
readonly Dictionary<string, object> items = new Dictionary<string, object>();
readonly Dictionary<string, DateTime> access = new Dictionary<string, DateTime>();
readonly Func<object> constructor;
public ThreadSafeCache(Func<object> constructor) {
this.constructor = constructor;
lock (cachesLock)
caches.Add(this);
}
public object Get(string key) {
lock (locker) {
object value;
if (!items.TryGetValue(key, out value)) {
value = constructor();
items[key] = value;
}
access[key] = DateTime.UtcNow;
return value;
}
}
internal static void CleanupTask(SchedulerTask task) {
lock (cachesLock) {
foreach (ThreadSafeCache cache in caches)
cache.CleanupOld();
}
}
void CleanupOld() {
List<string> free = null;
DateTime now = DateTime.UtcNow;
lock (locker) {
foreach (var kvp in access) {
// Has the cached item last been accessed in 5 minutes?
if ((now - kvp.Value).TotalMinutes <= 5) continue;
if (free == null) free = new List<string>();
free.Add(kvp.Key);
}
if (free == null) return;
foreach (string key in free) {
items.Remove(key);
access.Remove(key);
}
}
}
}
}

View File

@ -18,7 +18,6 @@
using System;
using System.CodeDom.Compiler;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace MCGalaxy.Util {

View File

@ -1,5 +1,5 @@
/*
Copyright 2015 MCGalaxy team
Copyright 2015 MCGalaxy
Dual-licensed under the Educational Community License, Version 2.0 and
the GNU General Public License, Version 3 (the "Licenses"); you may