@interopio/bridge 0.0.1-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/bin/bridge.js +9 -0
  2. package/gen/instance/GeneratedBuildInfo.ts +4 -0
  3. package/license.md +5 -0
  4. package/package.json +40 -0
  5. package/readme.md +10 -0
  6. package/src/cluster/Address.ts +57 -0
  7. package/src/cluster/Cluster.ts +13 -0
  8. package/src/cluster/Endpoint.ts +5 -0
  9. package/src/cluster/Member.ts +9 -0
  10. package/src/cluster/MembershipListener.ts +6 -0
  11. package/src/config/Config.ts +100 -0
  12. package/src/config/DiscoveryConfig.ts +21 -0
  13. package/src/config/Duration.ts +168 -0
  14. package/src/config/KubernetesConfig.ts +7 -0
  15. package/src/config/NamedDiscoveryConfig.ts +17 -0
  16. package/src/config/Properties.ts +49 -0
  17. package/src/config/index.ts +1 -0
  18. package/src/discovery/SimpleDiscoveryNode.ts +14 -0
  19. package/src/discovery/index.ts +207 -0
  20. package/src/discovery/multicast/MulticastDiscoveryStrategy.ts +141 -0
  21. package/src/discovery/multicast/MulticastDiscoveryStrategyFactory.ts +30 -0
  22. package/src/discovery/multicast/MulticastProperties.ts +4 -0
  23. package/src/discovery/settings.ts +37 -0
  24. package/src/error/RequestFailure.ts +48 -0
  25. package/src/gossip/ApplicationState.ts +48 -0
  26. package/src/gossip/EndpointState.ts +141 -0
  27. package/src/gossip/FailureDetector.ts +235 -0
  28. package/src/gossip/Gossiper.ts +1133 -0
  29. package/src/gossip/HeartbeatState.ts +66 -0
  30. package/src/gossip/Messenger.ts +130 -0
  31. package/src/gossip/VersionedValue.ts +59 -0
  32. package/src/index.ts +3 -0
  33. package/src/instance/AddressPicker.ts +245 -0
  34. package/src/instance/BridgeNode.ts +141 -0
  35. package/src/instance/ClusterTopologyIntentTracker.ts +4 -0
  36. package/src/io/VersionedSerializer.ts +230 -0
  37. package/src/io/util.ts +117 -0
  38. package/src/kubernetes/DnsEndpointResolver.ts +70 -0
  39. package/src/kubernetes/KubernetesApiEndpointResolver.ts +111 -0
  40. package/src/kubernetes/KubernetesApiProvider.ts +75 -0
  41. package/src/kubernetes/KubernetesClient.ts +264 -0
  42. package/src/kubernetes/KubernetesConfig.ts +130 -0
  43. package/src/kubernetes/KubernetesDiscoveryStrategy.ts +30 -0
  44. package/src/kubernetes/KubernetesDiscoveryStrategyFactory.ts +71 -0
  45. package/src/kubernetes/KubernetesEndpointResolver.ts +43 -0
  46. package/src/kubernetes/KubernetesProperties.ts +22 -0
  47. package/src/license/BridgeLicenseValidator.ts +19 -0
  48. package/src/license/LicenseValidator.ts +114 -0
  49. package/src/license/types.ts +40 -0
  50. package/src/logging.ts +22 -0
  51. package/src/main.mts +53 -0
  52. package/src/net/Action.ts +143 -0
  53. package/src/net/AddressSerializer.ts +44 -0
  54. package/src/net/ByteBufferAllocator.ts +27 -0
  55. package/src/net/FrameDecoder.ts +314 -0
  56. package/src/net/FrameEncoder.ts +138 -0
  57. package/src/net/HandshakeProtocol.ts +143 -0
  58. package/src/net/InboundConnection.ts +108 -0
  59. package/src/net/InboundConnectionInitiator.ts +150 -0
  60. package/src/net/InboundMessageHandler.ts +377 -0
  61. package/src/net/InboundSink.ts +38 -0
  62. package/src/net/Message.ts +428 -0
  63. package/src/net/OutboundConnection.ts +1141 -0
  64. package/src/net/OutboundConnectionInitiator.ts +76 -0
  65. package/src/net/RequestCallbacks.ts +148 -0
  66. package/src/net/ResponseHandler.ts +30 -0
  67. package/src/net/ShareableBytes.ts +125 -0
  68. package/src/net/internal/AsyncResourceExecutor.ts +464 -0
  69. package/src/net/internal/AsyncSocketPromise.ts +37 -0
  70. package/src/net/internal/channel/ChannelHandlerAdapter.ts +99 -0
  71. package/src/net/internal/channel/types.ts +188 -0
  72. package/src/utils/bigint.ts +23 -0
  73. package/src/utils/buffer.ts +434 -0
  74. package/src/utils/clock.ts +148 -0
  75. package/src/utils/collections.ts +283 -0
  76. package/src/utils/crc.ts +39 -0
  77. package/src/utils/internal/IpAddressUtil.ts +161 -0
  78. package/src/utils/memory/BufferPools.ts +40 -0
  79. package/src/utils/network.ts +130 -0
  80. package/src/utils/promise.ts +38 -0
  81. package/src/utils/uuid.ts +5 -0
  82. package/src/utils/vint.ts +238 -0
  83. package/src/version/MemberVersion.ts +42 -0
  84. package/src/version/Version.ts +12 -0
@@ -0,0 +1,235 @@
1
+ import {type Address, addressAsString} from '../cluster/Address.ts';
2
+ import {ObjectMap} from '../utils/collections.ts';
3
+ import {preciseClock} from '../utils/clock.ts';
4
+ import {convert} from '../config/Duration.ts';
5
+ import getLogger from '../logging.ts';
6
+
7
+ export interface FailureDetector {
8
+
9
+ /**
10
+ * invoked by any entity (gossiper) wanting to interrogate the status of the endpoint.
11
+ *
12
+ * @param endpoint
13
+ */
14
+ interpret(endpoint: Address): void;
15
+
16
+ /**
17
+ * invoked by the receiver of the heartbeat (gossiper).
18
+ * @param endpoint endpoint being reported
19
+ */
20
+ report(endpoint: Address): void
21
+
22
+ /**
23
+ * remove an endpoint
24
+ */
25
+ remove(endpoint: Address): void
26
+
27
+ /**
28
+ * force conviction of the specified endpoint in the failure detector.
29
+ * @param endpoint endpoint to be convicted
30
+ */
31
+ forceConviction(endpoint: Address): void;
32
+
33
+
34
+ }
35
+
36
+
37
+ export interface IFailureDetectionEventListener {
38
+ /**
39
+ * Convict the specified endpoint
40
+ * @param endpoint endpoint to be convicted
41
+ * @param phi the value of phi with which the endpoint was convicted
42
+ */
43
+ convict(endpoint: Address, phi: number): void;
44
+ }
45
+
46
+ class ArrayBackedBoundedStats {
47
+ private readonly _arrivalIntervals: Array<bigint>;
48
+ private _sum: bigint = 0n;
49
+ private _index: number = 0;
50
+ private _full = false;
51
+ private _mean: number = 0.0;
52
+
53
+ constructor(size: number) {
54
+ this._arrivalIntervals = new Array<bigint>(size);
55
+ }
56
+
57
+ add(interval: bigint): void {
58
+ if (this._index === this._arrivalIntervals.length) {
59
+ this._full = true;
60
+ this._index = 0;
61
+ }
62
+ if (this._full) {
63
+ this._sum = this._sum - this._arrivalIntervals[this._index];
64
+ }
65
+
66
+ this._arrivalIntervals[this._index++] = interval;
67
+ this._sum += interval;
68
+
69
+ this._mean = Number(this._sum) / this.size();
70
+ }
71
+
72
+ private size(): number {
73
+ return this._full ? this._arrivalIntervals.length : this._index;
74
+ }
75
+
76
+ public get mean(): number {
77
+ return this._mean;
78
+ }
79
+
80
+ toString(): string {
81
+ return `${this._arrivalIntervals}`;
82
+ }
83
+
84
+ }
85
+
86
+ const logger = getLogger('gossip.fd');
87
+
88
+ const INITIAL_VALUE_NS = convert('nanoseconds', 2 * 1000/*gossiper interval*/, 'milliseconds');
89
+
90
+
91
+
92
+ class ArrivalWindow {
93
+ private static readonly MAX_INTERVAL_NS = ArrivalWindow.getMaxInterval();
94
+ private readonly _arrivalIntervals: ArrayBackedBoundedStats;
95
+ private _lastReportedPhi: number = Number.MIN_VALUE;
96
+ private _last: bigint = 0n;
97
+
98
+ constructor(size: number) {
99
+ this._arrivalIntervals = new ArrayBackedBoundedStats(size);
100
+ }
101
+
102
+ static getMaxInterval(): bigint {
103
+ return INITIAL_VALUE_NS;
104
+ }
105
+
106
+ add(now: bigint, endpoint: Address) {
107
+ if (this._last < 0n) {
108
+ throw new Error();
109
+ }
110
+ if (this._last > 0n) {
111
+ const interval = now - this._last;
112
+ if (interval <= ArrivalWindow.MAX_INTERVAL_NS) {
113
+ this._arrivalIntervals.add(interval);
114
+ logger.enabledFor(`trace`) && logger.debug(`Reporting Interval time for ${addressAsString(endpoint)}: ${interval}ns`);
115
+ }
116
+ else {
117
+ logger.enabledFor(`trace`) && logger.debug(`Ignoring Interval time for ${addressAsString(endpoint)}: ${interval}ns`);
118
+ }
119
+ }
120
+ else {
121
+ this._arrivalIntervals.add(INITIAL_VALUE_NS);
122
+ }
123
+ this._last = now;
124
+ }
125
+
126
+ get mean(): number {
127
+ return this._arrivalIntervals.mean;
128
+ }
129
+
130
+ get lastReportedPhi(): number {
131
+ return this._lastReportedPhi;
132
+ }
133
+
134
+ phi(now: bigint): number {
135
+ if (!(this._arrivalIntervals.mean > 0 && this._last > 0n)) {
136
+ throw new Error('mean and last should be > 0 (mean: ' + this._arrivalIntervals.mean + ', last: ' + this._last + ')');
137
+ }
138
+ const t = Number(now - this._last);
139
+ this._lastReportedPhi = t / this.mean;
140
+ return this._lastReportedPhi;
141
+ }
142
+ }
143
+
144
+ // "The Phi Accrual Failure Detector"
145
+ export const failureDetector: FailureDetector = new (class implements FailureDetector {
146
+ private readonly SAMPLE_SIZE = 1000;
147
+
148
+
149
+ private readonly PHI_FACTOR = 1.0 / Math.log(10.0);
150
+ private readonly arrivalSamples: Map<Address, ArrivalWindow> = new ObjectMap<Address, ArrivalWindow>();
151
+ private readonly listeners = new Array<IFailureDetectionEventListener>()
152
+
153
+ private lastPause: bigint = 0n;
154
+ private lastInterpret = preciseClock.now();
155
+
156
+ report(endpoint: Address) {
157
+
158
+ const now = preciseClock.now();
159
+ let arrivalWindow = this.arrivalSamples.get(endpoint);
160
+ if (arrivalWindow === undefined) {
161
+ arrivalWindow = new ArrivalWindow(this.SAMPLE_SIZE);
162
+ arrivalWindow.add(now, endpoint);
163
+
164
+ this.arrivalSamples.set(endpoint, arrivalWindow);
165
+ }
166
+ else {
167
+ arrivalWindow.add(now, endpoint);
168
+ }
169
+ if (logger.enabledFor('trace')) {
170
+ logger.debug(`Average for ${addressAsString(endpoint)}: ${arrivalWindow.mean}ns`);
171
+ }
172
+ }
173
+
174
+ interpret(endpoint: Address) {
175
+ const arrivalWindow = this.arrivalSamples.get(endpoint);
176
+ if (arrivalWindow === undefined) {
177
+ return;
178
+ }
179
+ const now = preciseClock.now();
180
+ const diff = now - this.lastInterpret;
181
+ this.lastInterpret = now;
182
+
183
+ if (diff > MAX_LOCAL_PAUSE_NS) {
184
+ logger.warn(`Not marking nodes down due to local pause of ${diff}ns > ${MAX_LOCAL_PAUSE_NS}ns`);
185
+ this.lastPause = now;
186
+ return;
187
+ }
188
+ if ((preciseClock.now() - this.lastPause) < MAX_LOCAL_PAUSE_NS) {
189
+ if (logger.enabledFor('debug')) {
190
+ logger.debug(`Still not marking nodes down due to local pause`);
191
+ }
192
+ return;
193
+ }
194
+
195
+ const phi = arrivalWindow.phi(now);
196
+ if (logger.enabledFor('trace')) {
197
+ logger.debug(`PHI for ${addressAsString(endpoint)}: ${phi}`);
198
+ }
199
+
200
+ if (this.PHI_FACTOR * phi > this.getPhiConvictThreshold()) {
201
+ if (logger.enabledFor('trace')) {
202
+ logger.debug(`Node ${addressAsString(endpoint)} phi ${this.PHI_FACTOR * phi} > ${this.getPhiConvictThreshold()}; intervals ${arrivalWindow}, mean: ${arrivalWindow.mean}ns`);
203
+ }
204
+ for (const listener of this.listeners) {
205
+ listener.convict(endpoint, phi);
206
+ }
207
+ }
208
+ else if (logger.enabledFor('debug') && (this.PHI_FACTOR * phi * DEBUG_PERCENTAGE /100.0 > this.getPhiConvictThreshold())) {
209
+ logger.debug(`PHI for ${addressAsString(endpoint)}: ${phi}`);
210
+ } else if (logger.enabledFor('trace')) {
211
+ logger.debug(`PHI for ${addressAsString(endpoint)}: ${phi}`);
212
+ }
213
+ }
214
+
215
+ forceConviction(endpoint: Address) {
216
+ if (logger.enabledFor('debug')) {
217
+ logger.debug(`Forcing conviction of ${addressAsString(endpoint)}`);
218
+ }
219
+ for (const listener of this.listeners) {
220
+ listener.convict(endpoint, this.getPhiConvictThreshold());
221
+ }
222
+ }
223
+
224
+ remove(endpoint: Address) {
225
+ this.arrivalSamples.delete(endpoint);
226
+ }
227
+
228
+ private getPhiConvictThreshold(): number {
229
+ return 8.0;
230
+ }
231
+
232
+
233
+ });
234
+ const MAX_LOCAL_PAUSE_NS = convert('nanoseconds', 5000, 'milliseconds');
235
+ const DEBUG_PERCENTAGE = 80;