Start using read locks.

This commit is contained in:
UnknownShadow200 2016-08-19 19:54:59 +10:00
parent 35c4e324b7
commit 36465e8f2e
9 changed files with 49 additions and 27 deletions

View File

@ -44,7 +44,7 @@ namespace MCGalaxy.Bots {
}
static void Save() {
var bots = SavedBots.ToArray();
BotProperties[] bots = SavedBots.ToArray();
string json = JsonConvert.SerializeObject(bots);
try {
File.WriteAllText("extra/bots.json", json);

View File

@ -53,7 +53,10 @@ namespace MCGalaxy.Commands {
Player who = PlayerInfo.Find(name);
if (who != null) {
FoundUser = true;
PerformHighlight(p, seconds, who.UndoBuffer);
UndoCache cache = who.UndoBuffer;
using (IDisposable locker = cache.ClearLock.AccquireReadLock()) {
HighlightBlocks(p, seconds, cache);
}
}
DateTime start = DateTime.UtcNow.AddTicks(-seconds * TimeSpan.TicksPerSecond);
@ -66,7 +69,7 @@ namespace MCGalaxy.Commands {
}
}
static void PerformHighlight(Player p, long seconds, UndoCache cache) {
static void HighlightBlocks(Player p, long seconds, UndoCache cache) {
UndoCacheNode node = cache.Tail;
if (node == null) return;

View File

@ -23,7 +23,7 @@ using MCGalaxy.Util;
namespace MCGalaxy.Drawing.Ops {
public class RedoSelfDrawOp : DrawOp {
public class RedoSelfDrawOp : DrawOp {
public override string Name { get { return "RedoSelf"; } }
/// <summary> Point in time that the /undo should go backwards up to. </summary>
@ -36,12 +36,19 @@ namespace MCGalaxy.Drawing.Ops {
public override IEnumerable<DrawOpBlock> Perform(Vec3S32[] marks, Player p, Level lvl, Brush brush) {
UndoCache cache = p.UndoBuffer;
UndoCacheNode node = cache.Tail;
if (node == null) yield break;
int timeDelta = (int)DateTime.UtcNow.Subtract(Server.StartTime).TotalSeconds;
using (IDisposable locker = cache.ClearLock.AccquireReadLock()) {
RedoBlocks(p);
}
yield break;
}
void RedoBlocks(Player p) {
UndoCache cache = p.UndoBuffer;
UndoCacheNode node = p.UndoBuffer.Tail;
if (node == null) return;
while (node != null) {
lvl = LevelInfo.FindExact(node.MapName);
Level lvl = LevelInfo.FindExact(node.MapName);
if (lvl == null || (p.level != null && !p.level.name.CaselessEq(lvl.name))) {
node = node.Prev; continue;
}
@ -55,7 +62,7 @@ namespace MCGalaxy.Drawing.Ops {
DateTime time = node.BaseTime.AddTicks(item.TimeDelta * TimeSpan.TicksPerSecond);
if (time > End) continue;
if (time < Start) { buffer.CheckIfSend(true); yield break; }
if (time < Start) { buffer.CheckIfSend(true); return; }
byte tile, extTile;
item.GetBlock(out tile, out extTile);
@ -67,7 +74,7 @@ namespace MCGalaxy.Drawing.Ops {
buffer.CheckIfSend(true);
node = node.Prev;
}
yield break;
return;
}
}
}

View File

@ -42,14 +42,18 @@ namespace MCGalaxy.Drawing.Ops {
public override long GetBlocksAffected(Level lvl, Vec3S32[] marks) { return -1; }
public override IEnumerable<DrawOpBlock> Perform(Vec3S32[] marks, Player p, Level lvl, Brush brush) {
PerformUndo(p, ref saveLevel);
UndoCache cache = p.UndoBuffer;
using (IDisposable locker = cache.ClearLock.AccquireReadLock()) {
UndoBlocks(p, ref saveLevel);
}
bool foundUser = false;
Vec3S32[] bounds = { Min, Max };
UndoFile.UndoPlayer(p, who.name.ToLower(), bounds, Start, ref foundUser);
yield break;
}
void PerformUndo(Player p, ref Level saveLvl) {
void UndoBlocks(Player p, ref Level saveLvl) {
UndoCache cache = who.UndoBuffer;
UndoCacheNode node = cache.Tail;
if (node == null) return;

View File

@ -68,7 +68,7 @@ namespace MCGalaxy.Gui {
UpdateListTimer.Elapsed += delegate {
try {
UpdateClientList(Player.players);
UpdateClientList(null);
UpdateMapList();
}
catch { } // needed for slower computers

View File

@ -56,7 +56,7 @@ namespace fNbt {
}
byte[] bytes = ZeroArray;
public new byte this[int tagIndex] {
public byte this[int tagIndex] {
get { return Value[tagIndex]; }
set { Value[tagIndex] = value; }
}
@ -153,7 +153,7 @@ namespace fNbt {
public override NbtTagType TagType { get { return NbtTagType.IntArray; } }
public int[] Value { get; set; }
public new int this[int tagIndex] {
public int this[int tagIndex] {
get { return Value[tagIndex]; }
set { Value[tagIndex] = value; }
}

View File

@ -18,12 +18,13 @@
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
namespace MCGalaxy.Util {
public sealed class UndoCache {
/// <summary> The oldest/first node in the cache. </summary>
/// <summary> The olded/first node in the cache. </summary>
public UndoCacheNode Head;
/// <summary> The newest/last node in the cache. </summary>
@ -35,14 +36,16 @@ namespace MCGalaxy.Util {
/// <summary> Last time this undo buffer was cleared. </summary>
public DateTime LastClear;
/// <summary> Used to sychronise clearing an undo cache. </summary>
public ReaderWriterLockSlim ClearLock = new ReaderWriterLockSlim();
public const int TimeDeltaMax = (1 << 13) - 1;
/// <summary> Appends an item to the cache. </summary>
public void Add(Level lvl, Player.UndoPos item) {
DateTime time = Server.StartTime.AddTicks(item.timeDelta * TimeSpan.TicksPerSecond);
if (Head == null) {
Head = UndoCacheNode.Make(lvl, time);
Tail = Head;
if (Tail == null) {
Tail = UndoCacheNode.Make(lvl, time); Head = Tail;
}
if (lvl.name != Tail.MapName || lvl.Width != Tail.Width || lvl.Height != Tail.Height ||
@ -60,15 +63,15 @@ namespace MCGalaxy.Util {
/// <summary> Removes all items from the cache and resets the state to default. </summary>
public void Clear() {
Count = 0;
if( Head == null ) return;
if (Tail == null) return;
LastClear = DateTime.UtcNow;
UndoCacheNode node = Head;
while( node != null ) {
UndoCacheNode node = Tail;
while (node != null) {
node.Items = null;
node = node.Next;
node = node.Prev;
}
Head = null; Tail = null;
Tail = null; Head = null;
}
}
@ -78,7 +81,7 @@ namespace MCGalaxy.Util {
public int Width, Height, Length;
public DateTime BaseTime;
public UndoCacheNode Prev, Next;
public UndoCacheNode Prev;
public List<UndoCacheItem> Items = new List<UndoCacheItem>();
public static UndoCacheNode Make(Level lvl, DateTime time) {

View File

@ -59,7 +59,11 @@ namespace MCGalaxy.Util {
int numFiles = Directory.GetFiles(playerDir).Length;
string path = Path.Combine(playerDir, numFiles + NewFormat.Extension);
NewFormat.SaveUndoData(p.UndoBuffer, path);
UndoCache cache = p.UndoBuffer;
using (IDisposable locker = cache.ClearLock.AccquireReadLock()) {
NewFormat.SaveUndoData(cache, path);
}
}
public static void UndoPlayer(Player p, string target, Vec3S32[] marks, DateTime start, ref bool FoundUser) {

View File

@ -70,6 +70,7 @@ namespace MCGalaxy.Util {
}
protected override void SaveUndoData(UndoCache buffer, string path) {
// TODO: should be writing Head first??
using (FileStream fs = File.Create(path)) {
BinaryWriter w = new BinaryWriter(fs);
long entriesPos = 0;