Exposed access to storage timestamp data.

This commit is contained in:
Justin Aquadro 2011-08-14 17:11:34 +00:00
parent ac9c88773c
commit fa804da8a6
5 changed files with 160 additions and 7 deletions

View file

@ -218,6 +218,22 @@ namespace Substrate
#endregion
/// <summary>
/// Gets the (last modified) timestamp of the underlying chunk file.
/// </summary>
/// <param name="cx">The global X-coordinate of a chunk.</param>
/// <param name="cz">The global Z-coordinate of a chunk.</param>
/// <returns>The last modified timestamp of the underlying chunk file.</returns>
public int GetChunkTimestamp (int cx, int cz)
{
ChunkFile cf = GetChunkFile(cx, cz);
if (cf == null) {
return 0;
}
return cf.GetModifiedTime();
}
#region IEnumerable<ChunkRef> Members
/// <summary>

View file

@ -284,6 +284,41 @@ namespace Substrate
}
}
/// <summary>
/// Gets the timestamp of the chunk from its underlying region file.
/// </summary>
/// <param name="cx">The global X-coordinate of a chunk.</param>
/// <param name="cz">The global Z-coordinate of a chunk.</param>
/// <returns>The timestamp of the chunk from its underlying region file.</returns>
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
public int GetChunkTimestamp (int cx, int cz)
{
Region r = GetRegion(cx, cz);
if (r == null) {
return 0;
}
return r.GetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK);
}
/// <summary>
/// Sets the timestamp of the chunk in its underlying region file.
/// </summary>
/// <param name="cx">The global X-coordinate of a chunk.</param>
/// <param name="cz">The global Z-coordinate of a chunk.</param>
/// <param name="timestamp">The new timestamp value.</param>
/// <remarks>This function will only update the timestamp of the chunk slot in the underlying region file. It will not update
/// any timestamp information in the chunk data itself.</remarks>
public void SetChunkTimestamp (int cx, int cz, int timestamp)
{
Region r = GetRegion(cx, cz);
if (r == null) {
return;
}
r.SetChunkTimestamp(cx & REGION_XMASK, cz & REGION_ZMASK, timestamp);
}
private ChunkRef GetChunkRefInRegion (Region r, int lcx, int lcz)
{
int cx = r.X * REGION_XLEN + lcx;

View file

@ -32,6 +32,11 @@ namespace Substrate.Core
File.Delete(_filename);
}
public int GetModifiedTime ()
{
return Timestamp(File.GetLastWriteTime(_filename));
}
public virtual Stream GetDataInputStream ()
{
try {
@ -92,5 +97,10 @@ namespace Substrate.Core
}
}
private int Timestamp (DateTime time)
{
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0);
return (int)((time - epoch).Ticks / (10000L * 1000L));
}
}
}

View file

@ -274,6 +274,13 @@ namespace Substrate.Core
return new ZlibStream(new ChunkBuffer(this, x, z), CompressionMode.Compress);
}
public Stream GetChunkDataOutputStream (int x, int z, int timestamp)
{
if (OutOfBounds(x, z)) return null;
return new ZlibStream(new ChunkBuffer(this, x, z, timestamp), CompressionMode.Compress);
}
/*
* lets chunk writing be multithreaded by not locking the whole file as a
* chunk is serializing -- only writes when serialization is over
@ -282,20 +289,39 @@ namespace Substrate.Core
private int x, z;
private RegionFile region;
public ChunkBuffer(RegionFile r, int x, int z) : base(8096) {
// super(8096); // initialize to 8KB
private int? _timestamp;
public ChunkBuffer(RegionFile r, int x, int z)
: base(8096)
{
this.region = r;
this.x = x;
this.z = z;
}
public ChunkBuffer (RegionFile r, int x, int z, int timestamp)
: this(r, x, z)
{
_timestamp = timestamp;
}
public override void Close() {
region.Write(x, z, this.GetBuffer(), (int)this.Length);
if (_timestamp == null) {
region.Write(x, z, this.GetBuffer(), (int)this.Length);
}
else {
region.Write(x, z, this.GetBuffer(), (int)this.Length, (int)_timestamp);
}
}
}
protected void Write (int x, int z, byte[] data, int length)
{
Write(x, z, data, length, Timestamp());
}
/* write a chunk at (x,z) with length bytes of data to disk */
protected void Write(int x, int z, byte[] data, int length) {
protected void Write(int x, int z, byte[] data, int length, int timestamp) {
try {
int offset = GetOffset(x, z);
int sectorNumber = offset >> 8;
@ -364,7 +390,7 @@ namespace Substrate.Core
SetOffset(x, z, (sectorNumber << 8) | sectorsNeeded);
}
}
SetTimestamp(x, z, Timestamp());
SetTimestamp(x, z, timestamp);
} catch (IOException e) {
Console.WriteLine(e.StackTrace);
}
@ -436,7 +462,12 @@ namespace Substrate.Core
return (int)((time - epoch).Ticks / (10000L * 1000L));
}
private void SetTimestamp(int x, int z, int value) {
public int GetTimestamp (int x, int z)
{
return chunkTimestamps[x + z * 32];
}
public void SetTimestamp(int x, int z, int value) {
chunkTimestamps[x + z * 32] = value;
file.Seek(SECTOR_BYTES + (x + z * 32) * 4, SeekOrigin.Begin);

View file

@ -254,6 +254,26 @@ namespace Substrate
/// <remarks>It is up to the programmer to ensure that the global coordinates defined within the chunk's tree
/// are consistent with the local coordinates of the region being written into.</remarks>
public bool SaveChunkTree (int lcx, int lcz, NbtTree tree)
{
return SaveChunkTree(lcx, lcz, tree, null);
}
/// <summary>
/// Saves an <see cref="NbtTree"/> for a chunk back to the region's data store at the given local coordinates and with the given timestamp.
/// </summary>
/// <param name="lcx">The local X-coordinate of the chunk within the region.</param>
/// <param name="lcz">The local Z-coordinate of the chunk within the region.</param>
/// <param name="tree">The <see cref="NbtTree"/> of a chunk to write back to the region.</param>
/// <param name="timestamp">The timestamp to write to the underlying region file for this chunk.</param>
/// <returns>True if the save succeeded.</returns>
/// <remarks>It is up to the programmer to ensure that the global coordinates defined within the chunk's tree
/// are consistent with the local coordinates of the region being written into.</remarks>
public bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int timestamp)
{
return SaveChunkTree(lcx, lcz, tree, timestamp);
}
private bool SaveChunkTree (int lcx, int lcz, NbtTree tree, int? timestamp)
{
if (!LocalBoundsCheck(lcx, lcz)) {
Region alt = GetForeignRegion(lcx, lcz);
@ -261,7 +281,10 @@ namespace Substrate
}
RegionFile rf = GetRegionFile();
Stream zipstr = rf.GetChunkDataOutputStream(lcx, lcz);
Stream zipstr = (timestamp == null)
? rf.GetChunkDataOutputStream(lcx, lcz)
: rf.GetChunkDataOutputStream(lcx, lcz, (int)timestamp);
if (zipstr == null) {
return false;
}
@ -563,6 +586,44 @@ namespace Substrate
get { return true; }
}
/// <summary>
/// Gets the timestamp of a chunk from the underlying region file.
/// </summary>
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
/// <returns>The timestamp of the chunk slot in the region.</returns>
/// <remarks>The value returned may differ from any timestamp stored in the chunk data itself.</remarks>
public int GetChunkTimestamp (int lcx, int lcz)
{
if (!LocalBoundsCheck(lcx, lcz)) {
Region alt = GetForeignRegion(lcx, lcz);
return (alt == null) ? 0 : alt.GetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz));
}
RegionFile rf = GetRegionFile();
return rf.GetTimestamp(lcx, lcz);
}
/// <summary>
/// Sets the timestamp of a chunk in the underlying region file.
/// </summary>
/// <param name="lcx">The local X-coordinate of a chunk relative to this region.</param>
/// <param name="lcz">The local Z-coordinate of a chunk relative to this region.</param>
/// <param name="timestamp">The new timestamp value.</param>
/// <remarks>This function will only update the timestamp of the chunk slot in the underlying region file. It will not update
/// any timestamp information in the chunk data itself.</remarks>
public void SetChunkTimestamp (int lcx, int lcz, int timestamp)
{
if (!LocalBoundsCheck(lcx, lcz)) {
Region alt = GetForeignRegion(lcx, lcz);
if (alt != null)
alt.SetChunkTimestamp(ForeignX(lcx), ForeignZ(lcz), timestamp);
}
RegionFile rf = GetRegionFile();
rf.SetTimestamp(lcx, lcz, timestamp);
}
#endregion
private bool LocalBoundsCheck (int lcx, int lcz)