Skip to content

Commit a821e84

Browse files
committed
Merge branch '5.x' of https://github.com/elastic/elasticsearch-net into 5.x
2 parents 5e019ad + c8de193 commit a821e84

File tree

21 files changed

+348
-44
lines changed

21 files changed

+348
-44
lines changed

src/Elasticsearch.Net/Auditing/AuditEvent.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ public enum AuditEvent
1818

1919
MaxTimeoutReached,
2020
MaxRetriesReached,
21-
BadRequest
21+
BadRequest,
22+
NoNodesAttempted,
2223
}
2324
}

src/Elasticsearch.Net/Configuration/ConnectionConfiguration.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,15 @@ private static void DefaultRequestDataCreated(RequestData response) { }
143143
private Action<RequestData> _onRequestDataCreated = DefaultRequestDataCreated;
144144
Action<RequestData> IConnectionConfigurationValues.OnRequestDataCreated => _onRequestDataCreated;
145145

146+
/// <summary>
147+
/// The default predicate for <see cref="IConnectionPool"/> implementations that return true for <see cref="IConnectionPool.SupportsReseeding"/>
148+
/// in which case master only nodes are excluded from API calls.
149+
/// </summary>
150+
private static bool DefaultReseedableNodePredicate(Node node) => !node.MasterOnlyNode;
151+
private static bool DefaultNodePredicate(Node node) => true;
152+
private Func<Node, bool> _nodePredicate = DefaultNodePredicate;
153+
Func<Node, bool> IConnectionConfigurationValues.NodePredicate => _nodePredicate;
154+
146155
private readonly NameValueCollection _queryString = new NameValueCollection();
147156
NameValueCollection IConnectionConfigurationValues.QueryStringParameters => _queryString;
148157

@@ -176,6 +185,8 @@ protected ConnectionConfiguration(IConnectionPool connectionPool, IConnection co
176185
this._sniffOnConnectionFault = true;
177186
this._sniffOnStartup = true;
178187
this._sniffLifeSpan = TimeSpan.FromHours(1);
188+
if (this._connectionPool.SupportsReseeding)
189+
this._nodePredicate = DefaultReseedableNodePredicate;
179190
}
180191

181192
private T Assign(Action<ConnectionConfiguration<T>> assigner) => Fluent.Assign((T)this, assigner);
@@ -363,6 +374,19 @@ public T BasicAuthentication(string userName, string password) =>
363374
/// </summary>
364375
public T EnableHttpPipelining(bool enabled = true) => Assign(a => a._enableHttpPipelining = enabled);
365376

377+
/// <summary>
378+
/// Register a predicate to select which nodes that you want to execute API calls on. Note that sniffing requests omit this predicate and always execute on all nodes.
379+
/// When using an <see cref="IConnectionPool"/> implementation that supports reseeding of nodes, this will default to omitting master only node from regular API calls.
380+
/// When using static or single node connection pooling it is assumed the list of node you instantiate the client with should be taken verbatim.
381+
/// </summary>
382+
/// <param name="predicate">Return true if you want the node to be used for API calls</param>
383+
public T NodePredicate(Func<Node, bool> predicate)
384+
{
385+
if (predicate == null) return (T) this;
386+
this._nodePredicate = predicate;
387+
return (T)this;
388+
}
389+
366390
/// <summary>
367391
/// Turns on settings that aid in debugging like DisableDirectStreaming() and PrettyJson()
368392
/// so that the original request and response JSON can be inspected.

src/Elasticsearch.Net/Configuration/IConnectionConfigurationValues.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,12 @@ public interface IConnectionConfigurationValues : IDisposable
171171
/// received.
172172
/// </summary>
173173
TimeSpan? KeepAliveInterval { get; }
174+
175+
/// <summary>
176+
/// Register a predicate to select which nodes that you want to execute API calls on. Note that sniffing requests omit this predicate and always execute on all nodes.
177+
/// When using an <see cref="IConnectionPool"/> implementation that supports reseeding of nodes, this will default to omitting master only node from regular API calls.
178+
/// When using static or single node connection pooling it is assumed the list of node you instantiate the client with should be taken verbatim.
179+
/// </summary>
180+
Func<Node, bool> NodePredicate { get; }
174181
}
175182
}

src/Elasticsearch.Net/ConnectionPool/IConnectionPool.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ namespace Elasticsearch.Net
66
public interface IConnectionPool : IDisposable
77
{
88
/// <summary>
9-
/// Returns a readonly constant view of all the nodes in the cluster, this might involve creating copies of the nodes e.g
10-
/// if you are using the sniffing connectionpool. If you do not need an isolated copy of the nodes please read `CreateView()` to completion
9+
/// Returns a readonly constant view of all the nodes in the cluster, this might involve creating copies of the nodes e.g
10+
/// if you are using the sniffing connectionpool. If you do not need an isolated copy of the nodes please read <see cref="CreateView"/> to completion
1111
/// </summary>
1212
IReadOnlyCollection<Node> Nodes { get; }
1313

@@ -17,7 +17,7 @@ public interface IConnectionPool : IDisposable
1717
/// in the connection settings
1818
/// </summary>
1919
int MaxRetries { get; }
20-
20+
2121
/// <summary>
2222
/// Signals that this implemenation can accept new nodes
2323
/// </summary>
@@ -50,4 +50,4 @@ public interface IConnectionPool : IDisposable
5050
void Reseed(IEnumerable<Node> nodes);
5151

5252
}
53-
}
53+
}

src/Elasticsearch.Net/ConnectionPool/Node.cs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
using System;
2+
using System.Collections.Generic;
3+
using System.Collections.ObjectModel;
24
using Purify;
35

46
namespace Elasticsearch.Net
@@ -32,12 +34,22 @@ public Node(Uri uri)
3234
/// <summary>Indicates whether this node is master eligible, defaults to true when unknown/unspecified</summary>
3335
public bool MasterEligible { get; set; }
3436

37+
/// <summary>Indicates whether this node is allowed to run ingest pipelines, defaults to true when unknown/unspecified</summary>
38+
public bool IngestEnabled { get; set; }
39+
40+
public bool MasterOnlyNode => this.MasterEligible && !this.HoldsData;
41+
42+
public bool ClientNode => !this.MasterEligible && !this.HoldsData;
43+
3544
/// <summary>The id of the node, defaults to null when unknown/unspecified</summary>
3645
public string Id { get; set; }
3746

3847
/// <summary>The name of the node, defaults to null when unknown/unspecified</summary>
3948
public string Name { get; set; }
4049

50+
private static readonly IReadOnlyDictionary<string, string> EmptySettings = new ReadOnlyDictionary<string, string>(new Dictionary<string, string>());
51+
public IReadOnlyDictionary<string, string> Settings { get; set; } = EmptySettings;
52+
4153
/// <summary> The number of failed attempts trying to use this node, resets when a node is marked alive</summary>
4254
public int FailedAttempts { get; private set; }
4355

@@ -74,15 +86,17 @@ public Node Clone() =>
7486
MasterEligible = this.MasterEligible,
7587
FailedAttempts = this.FailedAttempts,
7688
DeadUntil = this.DeadUntil,
77-
IsAlive = this.IsAlive
89+
IsAlive = this.IsAlive,
90+
Settings = this.Settings,
91+
IngestEnabled = this.IngestEnabled,
92+
HttpEnabled = this.HttpEnabled
7893
};
7994

8095

81-
// ReSharper disable once PossibleNullReferenceException
82-
public static bool operator ==(Node left, Node right) => left.Equals(right);
96+
public static bool operator ==(Node left, Node right) =>
97+
ReferenceEquals(left, null) ? ReferenceEquals(right, null) : left.Equals(right);
8398

84-
// ReSharper disable once PossibleNullReferenceException
85-
public static bool operator !=(Node left, Node right) => !left.Equals(right);
99+
public static bool operator !=(Node left, Node right) => !(left == right);
86100

87101
public static implicit operator Node(Uri uri) => new Node(uri);
88102

src/Elasticsearch.Net/ConnectionPool/SingleNodeConnectionPool.cs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,31 @@ namespace Elasticsearch.Net
55
{
66
public class SingleNodeConnectionPool : IConnectionPool
77
{
8+
/// <inheritdoc/>
89
public int MaxRetries => 0;
910

11+
/// <inheritdoc/>
1012
public bool SupportsReseeding => false;
13+
14+
/// <inheritdoc/>
1115
public bool SupportsPinging => false;
1216

17+
/// <inheritdoc/>
1318
public void Reseed(IEnumerable<Node> nodes) { } //ignored
14-
19+
20+
/// <inheritdoc/>
1521
public bool UsingSsl { get; }
1622

23+
/// <inheritdoc/>
1724
public bool SniffedOnStartup { get { return true; } set { } }
1825

26+
/// <inheritdoc/>
1927
public IReadOnlyCollection<Node> Nodes { get; }
2028

29+
/// <inheritdoc/>
2130
public DateTime LastUpdate { get; }
2231

32+
/// <inheritdoc/>
2333
public SingleNodeConnectionPool(Uri uri, IDateTimeProvider dateTimeProvider = null)
2434
{
2535
var node = new Node(uri);
@@ -28,6 +38,7 @@ public SingleNodeConnectionPool(Uri uri, IDateTimeProvider dateTimeProvider = nu
2838
this.LastUpdate = (dateTimeProvider ?? DateTimeProvider.Default).Now();
2939
}
3040

41+
/// <inheritdoc/>
3142
public IEnumerable<Node> CreateView(Action<AuditEvent, Node> audit = null) => this.Nodes;
3243

3344
void IDisposable.Dispose() => this.DisposeManagedResources();

src/Elasticsearch.Net/ConnectionPool/SniffingConnectionPool.cs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ public class SniffingConnectionPool : StaticConnectionPool
99
{
1010
private readonly ReaderWriterLockSlim _readerWriter = new ReaderWriterLockSlim();
1111

12+
/// <inheritdoc/>
1213
public override bool SupportsReseeding => true;
14+
15+
/// <inheritdoc/>
1316
public override bool SupportsPinging => true;
1417

1518
public SniffingConnectionPool(IEnumerable<Uri> uris, bool randomize = true, IDateTimeProvider dateTimeProvider = null)
@@ -20,6 +23,13 @@ public SniffingConnectionPool(IEnumerable<Node> nodes, bool randomize = true, ID
2023
: base(nodes, randomize, dateTimeProvider)
2124
{ }
2225

26+
public SniffingConnectionPool(IEnumerable<Node> nodes, Func<Node, bool> predicate, bool randomize = true, IDateTimeProvider dateTimeProvider = null)
27+
: base(nodes, randomize, dateTimeProvider)
28+
{ }
29+
30+
private static bool DefaultPredicate(Node node) => !node.MasterOnlyNode;
31+
32+
/// <inheritdoc/>
2333
public override IReadOnlyCollection<Node> Nodes
2434
{
2535
get
@@ -38,6 +48,7 @@ public override IReadOnlyCollection<Node> Nodes
3848
}
3949
}
4050

51+
/// <inheritdoc/>
4152
public override void Reseed(IEnumerable<Node> nodes)
4253
{
4354
if (!nodes.HasAny()) return;
@@ -60,6 +71,7 @@ public override void Reseed(IEnumerable<Node> nodes)
6071
}
6172
}
6273

74+
/// <inheritdoc/>
6375
public override IEnumerable<Node> CreateView(Action<AuditEvent, Node> audit = null)
6476
{
6577
try
@@ -79,4 +91,4 @@ protected override void DisposeManagedResources()
7991
base.DisposeManagedResources();
8092
}
8193
}
82-
}
94+
}

src/Elasticsearch.Net/ConnectionPool/StaticConnectionPool.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,27 @@ public class StaticConnectionPool : IConnectionPool
1313

1414
protected List<Node> InternalNodes { get; set; }
1515

16+
/// <inheritdoc/>
1617
public virtual IReadOnlyCollection<Node> Nodes => this.InternalNodes;
1718

19+
/// <inheritdoc/>
1820
public int MaxRetries => this.InternalNodes.Count - 1;
1921

22+
/// <inheritdoc/>
2023
public virtual bool SupportsReseeding => false;
24+
/// <inheritdoc/>
2125
public virtual bool SupportsPinging => true;
2226

27+
/// <inheritdoc/>
2328
public virtual void Reseed(IEnumerable<Node> nodes) { } //ignored
2429

30+
/// <inheritdoc/>
2531
public bool UsingSsl { get; }
2632

33+
/// <inheritdoc/>
2734
public bool SniffedOnStartup { get; set; }
2835

36+
/// <inheritdoc/>
2937
public DateTime LastUpdate { get; protected set; }
3038

3139
public StaticConnectionPool(IEnumerable<Uri> uris, bool randomize = true, IDateTimeProvider dateTimeProvider = null)
@@ -101,4 +109,4 @@ public virtual IEnumerable<Node> CreateView(Action<AuditEvent, Node> audit = nul
101109

102110
protected virtual void DisposeManagedResources() { }
103111
}
104-
}
112+
}

src/Elasticsearch.Net/Exceptions/ElasticsearchClientException.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ public string DebugInformation
4444
{
4545
failureReason = "Unrecoverable/Unexpected " + this.AuditTrail.Last().Event.GetStringValue();
4646
}
47+
var path = Request.Uri != null ? Request.Uri.ToString() : Request.Path + " on an empty node, likely a node predicate on ConnectionSettings not matching ANY nodes";
4748

48-
sb.AppendLine($"# FailureReason: {failureReason} while attempting {Request.Method.GetStringValue()} {Request.Uri}");
49+
sb.AppendLine($"# FailureReason: {failureReason} while attempting {Request.Method.GetStringValue()} on {path}");
4950
if (this.Response != null)
5051
ResponseStatics.DebugInformationBuilder(this.Response, sb);
5152
else

src/Elasticsearch.Net/Responses/ElasticsearchResponse.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public static void DebugAuditTrail(List<Audit> auditTrail, StringBuilder sb)
4848
sb.Append($" - [{a.i + 1}] {audit.Event.GetStringValue()}:");
4949
if (audit.Node?.Uri != null) sb.Append($" Node: {audit.Node.Uri}");
5050
if (audit.Exception != null) sb.Append($" Exception: {audit.Exception.GetType().Name}");
51-
sb.AppendLine($" Took: {(audit.Ended - audit.Started)}");
51+
sb.AppendLine($" Took: {(audit.Ended - audit.Started).ToString()}");
5252
}
5353
}
5454
}

0 commit comments

Comments
 (0)