Skip to content

Commit

Permalink
Refactor frontend message handling
Browse files Browse the repository at this point in the history
* Frontend messages have been replaced with simple function calls on
  the connector. Rather than populating a message instance and then
  writing it, we now just call a method with parameters.
* Considerable reduction in code and complexity, plus no more
  need to cache frontend message instances on the connector.
* Made naming more consistent: write methods don't (necessarily)
  flush, etc.
* Refactored SASL authentication to better separate protocol-level
  logic from encryption logic.
* Enabled C# 8 for static local functions.

Closes #2353
  • Loading branch information
roji committed Mar 28, 2019
1 parent d5a4393 commit befb61b
Show file tree
Hide file tree
Showing 28 changed files with 743 additions and 1,153 deletions.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

<!-- Language configuration -->
<PropertyGroup>
<LangVersion>latest</LangVersion>
<LangVersion>8.0</LangVersion>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>

Expand Down
1 change: 1 addition & 0 deletions Npgsql.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Npgsql_0027s/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=PGTZ/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Postgre/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Pregenerated/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=P_0020keepaliv/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=resultset/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=UNLISTEN/@EntryIndexedValue">True</s:Boolean>
Expand Down
13 changes: 1 addition & 12 deletions src/Npgsql/BackendMessages/CopyMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,10 @@ internal CopyDataMessage Load(int len)
}
}

/// <remarks>
/// Note: This message is both a frontend and a backend message
/// </remarks>
class CopyDoneMessage : SimpleFrontendMessage, IBackendMessage
class CopyDoneMessage : IBackendMessage
{
public BackendMessageCode Code => BackendMessageCode.CopyDone;
internal static readonly CopyDoneMessage Instance = new CopyDoneMessage();
CopyDoneMessage() { }

internal override int Length => 5;

internal override void WriteFully(NpgsqlWriteBuffer buf)
{
buf.WriteByte((byte)BackendMessageCode.CopyDone);
buf.WriteInt32(4);
}
}
}
70 changes: 15 additions & 55 deletions src/Npgsql/Common.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,61 +11,6 @@ interface IBackendMessage
BackendMessageCode Code { get; }
}

/// <summary>
/// Base class for all classes which represent a message sent to the PostgreSQL backend.
/// Concrete classes which directly inherit this represent arbitrary-length messages which can chunked.
/// </summary>
abstract class FrontendMessage
{
/// <param name="buf">the buffer into which to write the message.</param>
/// <param name="async"></param>
/// <returns>
/// Whether there was enough space in the buffer to contain the entire message.
/// If false, the buffer should be flushed and write should be called again.
/// </returns>
internal abstract Task Write(NpgsqlWriteBuffer buf, bool async);

/// <summary>
/// Returns how many messages PostgreSQL is expected to send in response to this message.
/// Used for message prepending.
/// </summary>
internal virtual int ResponseMessageCount => 1;
}

/// <summary>
/// Represents a simple frontend message which is typically small and fits well within
/// the write buffer. The message is first queries for the number of bytes it requires,
/// and then writes itself out.
/// </summary>
abstract class SimpleFrontendMessage : FrontendMessage
{
/// <summary>
/// Returns the number of bytes needed to write this message.
/// </summary>
internal abstract int Length { get; }

/// <summary>
/// Writes the message contents into the buffer.
/// </summary>
internal abstract void WriteFully(NpgsqlWriteBuffer buf);

internal sealed override Task Write(NpgsqlWriteBuffer buf, bool async)
{
if (buf.WriteSpaceLeft < Length)
return FlushAndWrite(buf, async);
Debug.Assert(Length <= buf.WriteSpaceLeft, $"Message of type {GetType().Name} has length {Length} which is bigger than the buffer ({buf.WriteSpaceLeft})");
WriteFully(buf);
return Task.CompletedTask;
}

async Task FlushAndWrite(NpgsqlWriteBuffer buf, bool async)
{
await buf.Flush(async);
Debug.Assert(Length <= buf.WriteSpaceLeft, $"Message of type {GetType().Name} has length {Length} which is bigger than the buffer ({buf.WriteSpaceLeft})");
WriteFully(buf);
}
}

enum BackendMessageCode : byte
{
AuthenticationRequest = (byte)'R',
Expand Down Expand Up @@ -95,6 +40,21 @@ enum BackendMessageCode : byte
RowDescription = (byte)'T',
}

static class FrontendMessageCode
{
internal const byte Describe = (byte)'D';
internal const byte Sync = (byte)'S';
internal const byte Execute = (byte)'E';
internal const byte Parse = (byte)'P';
internal const byte Bind = (byte)'B';
internal const byte Close = (byte)'C';
internal const byte Query = (byte)'Q';
internal const byte CopyDone = (byte)'c';
internal const byte CopyFail = (byte)'f';
internal const byte Terminate = (byte)'X';
internal const byte Password = (byte)'p';
}

enum StatementOrPortal : byte
{
Statement = (byte)'S',
Expand Down
137 changes: 0 additions & 137 deletions src/Npgsql/FrontendMessages/BindMessage.cs

This file was deleted.

32 changes: 0 additions & 32 deletions src/Npgsql/FrontendMessages/CancelRequestMessage.cs

This file was deleted.

41 changes: 0 additions & 41 deletions src/Npgsql/FrontendMessages/CloseMessage.cs

This file was deleted.

39 changes: 0 additions & 39 deletions src/Npgsql/FrontendMessages/CopyFailMessage.cs

This file was deleted.

Loading

0 comments on commit befb61b

Please sign in to comment.