Skip to content

Commit

Permalink
Interfaces to enable chunk data transformation plugins
Browse files Browse the repository at this point in the history
Added: transform interfaces/classes
Added: new operation to set the active transform
Added: Encryption_AesGcm transform type
  • Loading branch information
shaan1337 committed Jun 10, 2024
1 parent ea86e9b commit 3f37588
Show file tree
Hide file tree
Showing 9 changed files with 154 additions and 0 deletions.
5 changes: 5 additions & 0 deletions src/EventStore.Plugins/Authorization/Operations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ public static class Gossip {
public static readonly OperationDefinition Update = new(Resource, "update");
public static readonly OperationDefinition ClientRead = new($"{Resource}/client", "read");
}

public static class Transform {
const string Resource = "transform";
public static readonly OperationDefinition Set = new(Resource, "set");
}
}

public static class Streams {
Expand Down
43 changes: 43 additions & 0 deletions src/EventStore.Plugins/Transforms/ChunkDataReadStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using System;
using System.IO;

namespace EventStore.Plugins.Transforms;

public class ChunkDataReadStream(Stream chunkFileStream) : Stream {
public Stream ChunkFileStream => chunkFileStream;

public sealed override bool CanRead => true;
public sealed override bool CanSeek => true;
public sealed override bool CanWrite => false;
public sealed override void Write(byte[] buffer, int offset, int count) => throw new InvalidOperationException();
public sealed override void Flush() => throw new InvalidOperationException();
public sealed override void SetLength(long value) => throw new InvalidOperationException();
public override long Length => throw new NotSupportedException();

// reads must always return exactly `count` bytes as we never read past the (flushed) writer checkpoint
public override int Read(byte[] buffer, int offset, int count) => ChunkFileStream.Read(buffer, offset, count);

// seeks need to support only `SeekOrigin.Begin`
public override long Seek(long offset, SeekOrigin origin) {
if (origin != SeekOrigin.Begin)
throw new NotSupportedException();

return ChunkFileStream.Seek(offset, origin);
}

public override long Position {
get => ChunkFileStream.Position;
set => ChunkFileStream.Position = value;
}

protected override void Dispose(bool disposing) {
try {
if (!disposing)
return;

chunkFileStream.Dispose();
} finally {
base.Dispose(disposing);
}
}
}
61 changes: 61 additions & 0 deletions src/EventStore.Plugins/Transforms/ChunkDataWriteStream.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
using System;
using System.IO;
using System.Security.Cryptography;

namespace EventStore.Plugins.Transforms;

public class ChunkDataWriteStream(Stream chunkFileStream, HashAlgorithm checksumAlgorithm) : Stream {
public Stream ChunkFileStream => chunkFileStream;
public HashAlgorithm ChecksumAlgorithm => checksumAlgorithm;

public sealed override bool CanRead => false;
public sealed override bool CanSeek => false;
public sealed override bool CanWrite => true;
public sealed override int Read(byte[] buffer, int offset, int count) => throw new InvalidOperationException();
public sealed override long Seek(long offset, SeekOrigin origin) => throw new InvalidOperationException();

public override void Write(byte[] buffer, int offset, int count) {
ChunkFileStream.Write(buffer, offset, count);
ChecksumAlgorithm.TransformBlock(buffer, 0, count, null, 0);
}

public override void Flush() => ChunkFileStream.Flush();
public override void SetLength(long value) => ChunkFileStream.SetLength(value);
public override long Length => ChunkFileStream.Length;
public override long Position {
get => ChunkFileStream.Position;
set {
if (ChunkFileStream.Position != 0)
throw new InvalidOperationException("Writer's position can only be moved from 0 to a higher value.");

ReadAndChecksum(value);

if (ChunkFileStream.Position != value)
throw new Exception($"Writer's position ({ChunkFileStream.Position:N0}) is not at the expected position ({value:N0})");
}
}

private void ReadAndChecksum(long count) {
var buffer = new byte[4096];
long toRead = count;
while (toRead > 0) {
int read = ChunkFileStream.Read(buffer, 0, (int)Math.Min(toRead, buffer.Length));
if (read == 0)
break;

ChecksumAlgorithm.TransformBlock(buffer, 0, read, null, 0);
toRead -= read;
}
}

protected override void Dispose(bool disposing) {
try {
if (!disposing)
return;

chunkFileStream.Dispose();
} finally {
base.Dispose(disposing);
}
}
}
5 changes: 5 additions & 0 deletions src/EventStore.Plugins/Transforms/IChunkReadTransform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace EventStore.Plugins.Transforms;

public interface IChunkReadTransform {
ChunkDataReadStream TransformData(ChunkDataReadStream stream);
}
6 changes: 6 additions & 0 deletions src/EventStore.Plugins/Transforms/IChunkTransform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace EventStore.Plugins.Transforms;

public interface IChunkTransform {
IChunkReadTransform Read { get; }
IChunkWriteTransform Write { get; }
}
12 changes: 12 additions & 0 deletions src/EventStore.Plugins/Transforms/IChunkTransformFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System;
using System.IO;

namespace EventStore.Plugins.Transforms;

public interface IChunkTransformFactory {
TransformType Type { get; }
int TransformDataPosition(int dataPosition);
ReadOnlyMemory<byte> CreateTransformHeader();
ReadOnlyMemory<byte> ReadTransformHeader(Stream stream);
IChunkTransform CreateTransform(ReadOnlyMemory<byte> transformHeader);
}
9 changes: 9 additions & 0 deletions src/EventStore.Plugins/Transforms/IChunkWriteTransform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System;

namespace EventStore.Plugins.Transforms;

public interface IChunkWriteTransform {
ChunkDataWriteStream TransformData(ChunkDataWriteStream stream);
void CompleteData(int footerSize, int alignmentSize);
void WriteFooter(ReadOnlySpan<byte> footer, out int fileSize);
}
7 changes: 7 additions & 0 deletions src/EventStore.Plugins/Transforms/IDbTransform.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace EventStore.Plugins.Transforms;

public interface IDbTransform {
string Name { get; }
TransformType Type { get; }
IChunkTransformFactory ChunkFactory { get; }
}
6 changes: 6 additions & 0 deletions src/EventStore.Plugins/Transforms/TransformType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace EventStore.Plugins.Transforms;

public enum TransformType {
Identity = 0,
Encryption_AesGcm = 1,
}

0 comments on commit 3f37588

Please sign in to comment.