vortexpy 4.0.23__py3-none-any.whl
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.
- vortex/DataWrapTuple.py +27 -0
- vortex/DeferUtil.py +224 -0
- vortex/Jsonable.py +304 -0
- vortex/Payload.py +115 -0
- vortex/PayloadEndpoint.py +216 -0
- vortex/PayloadEndpointTest.py +164 -0
- vortex/PayloadEnvelope.py +166 -0
- vortex/PayloadFilterKeys.py +15 -0
- vortex/PayloadIO.py +152 -0
- vortex/PayloadPriority.py +11 -0
- vortex/PayloadResponse.py +173 -0
- vortex/PayloadResponseTest.py +39 -0
- vortex/PayloadTest.py +136 -0
- vortex/PerformTestActionTuple.py +30 -0
- vortex/SerialiseUtil.py +273 -0
- vortex/TestTuple.py +61 -0
- vortex/Tuple.py +968 -0
- vortex/TupleAction.py +72 -0
- vortex/TupleActionVortex.py +5 -0
- vortex/TupleDataForTest.py +25 -0
- vortex/TuplePerfTest.py +71 -0
- vortex/TuplePolymorphicTupleTypeFieldArgTest.py +74 -0
- vortex/TupleRestfulTest.py +140 -0
- vortex/TupleSelector.py +105 -0
- vortex/TupleTest.py +127 -0
- vortex/VortexABC.py +55 -0
- vortex/VortexClientHttp.py +308 -0
- vortex/VortexClientHttpTest.py +71 -0
- vortex/VortexClientTcp.py +355 -0
- vortex/VortexClientWebsocketFactory.py +383 -0
- vortex/VortexConnectionABC.py +88 -0
- vortex/VortexFactory.py +932 -0
- vortex/VortexPayloadProtocol.py +180 -0
- vortex/VortexServer.py +367 -0
- vortex/VortexServerConnection.py +127 -0
- vortex/VortexServerHttpResource.py +193 -0
- vortex/VortexServerTcp.py +104 -0
- vortex/VortexServerWebsocket.py +287 -0
- vortex/VortexTcpMemoryLeakPayloadTest.py +611 -0
- vortex/VortexTcpMemoryLeakRawTest.py +87 -0
- vortex/VortexTest.py +22 -0
- vortex/VortexUtil.py +314 -0
- vortex/VortexWritePushProducer.py +321 -0
- vortex/__init__.py +10 -0
- vortex/data_loader/TupleDataLiveLockManager.py +383 -0
- vortex/data_loader/TupleDataLoader.py +326 -0
- vortex/data_loader/TupleDataLoaderDelegate.py +90 -0
- vortex/data_loader/TupleDataLoaderTupleABC.py +10 -0
- vortex/data_loader/TupleDataLoaderTuples.py +53 -0
- vortex/data_loader/__init__.py +0 -0
- vortex/event_bus/TupleChangeEventABC.py +15 -0
- vortex/event_bus/TupleChangeEventBus.py +192 -0
- vortex/event_bus/TupleChangeEventBusObserverABC.py +11 -0
- vortex/event_bus/__init__.py +0 -0
- vortex/handler/TupleActionProcessor.py +270 -0
- vortex/handler/TupleActionProcessorProxy.py +218 -0
- vortex/handler/TupleActionProcessorTestHandler.py +27 -0
- vortex/handler/TupleDataActionClient.py +67 -0
- vortex/handler/TupleDataObservableCache.py +201 -0
- vortex/handler/TupleDataObservableHandler.py +371 -0
- vortex/handler/TupleDataObservableProxyHandler.py +340 -0
- vortex/handler/TupleDataObservableTestHandler.py +60 -0
- vortex/handler/TupleDataObserverClient.py +158 -0
- vortex/handler/VortexJSTupleLoaderTestHandler.py +42 -0
- vortex/handler/__init__.py +0 -0
- vortex/restful/GzippedDataHttpClient.py +170 -0
- vortex/restful/GzippedDataHttpClientTest.py +103 -0
- vortex/restful/GzippedPayloadHttpClient.py +181 -0
- vortex/restful/RestfulHttpClient.py +107 -0
- vortex/restful/RestfulHttpClientTest.py +60 -0
- vortex/restful/RestfulResource.py +153 -0
- vortex/restful/RestfulResourceTest.py +100 -0
- vortex/restful/__init__.py +0 -0
- vortex/rpc/RPC.py +446 -0
- vortex/rpc/RPCTest.py +12 -0
- vortex/rpc/__init__.py +0 -0
- vortex/sqla_orm/OrmCrudHandler.py +431 -0
- vortex/sqla_orm/TupleProviderForDb.py +42 -0
- vortex/sqla_orm/VortexTupleJson.py +24 -0
- vortex/sqla_orm/__init__.py +0 -0
- vortex/storage/TupleStorageSqlite.py +359 -0
- vortex/storage/__init__.py +0 -0
- vortexpy-4.0.23.dist-info/LICENSE +21 -0
- vortexpy-4.0.23.dist-info/METADATA +43 -0
- vortexpy-4.0.23.dist-info/RECORD +87 -0
- vortexpy-4.0.23.dist-info/WHEEL +5 -0
- vortexpy-4.0.23.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
"""
|
|
2
|
+
* Created by Synerty Pty Ltd
|
|
3
|
+
*
|
|
4
|
+
* This software is open source, the MIT license applies.
|
|
5
|
+
*
|
|
6
|
+
* Website : http://www.synerty.com
|
|
7
|
+
* Support : support@synerty.com
|
|
8
|
+
"""
|
|
9
|
+
import gc
|
|
10
|
+
import os
|
|
11
|
+
import tracemalloc
|
|
12
|
+
from collections import deque
|
|
13
|
+
from random import random
|
|
14
|
+
from typing import Optional
|
|
15
|
+
|
|
16
|
+
import psutil
|
|
17
|
+
from twisted.internet import reactor
|
|
18
|
+
from twisted.internet.defer import inlineCallbacks, Deferred
|
|
19
|
+
from twisted.python.failure import Failure
|
|
20
|
+
from twisted.trial import unittest
|
|
21
|
+
|
|
22
|
+
from vortex.Payload import Payload
|
|
23
|
+
from vortex.PayloadEndpoint import PayloadEndpoint
|
|
24
|
+
from vortex.VortexClientTcp import VortexClientTcp
|
|
25
|
+
from vortex.VortexServer import VortexServer
|
|
26
|
+
from vortex.VortexServerTcp import VortexTcpServerFactory
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MemoryCheckerTestMixin:
|
|
30
|
+
def _memMark(self):
|
|
31
|
+
self._process = psutil.Process(os.getpid())
|
|
32
|
+
unreachable = gc.collect()
|
|
33
|
+
self._initialMem = self._process.memory_info().rss
|
|
34
|
+
self._initialUnreachable = unreachable
|
|
35
|
+
self._lastMem = self._initialMem
|
|
36
|
+
|
|
37
|
+
def _memCheck(self, grace=0):
|
|
38
|
+
unreachable = gc.collect()
|
|
39
|
+
self.assertLessEqual(
|
|
40
|
+
unreachable,
|
|
41
|
+
self._initialUnreachable,
|
|
42
|
+
"The garbage collector couldn't release everything",
|
|
43
|
+
)
|
|
44
|
+
self._memPrintIncrease()
|
|
45
|
+
memNow = self._process.memory_info().rss
|
|
46
|
+
self.assertLessEqual(memNow, self._initialMem + grace)
|
|
47
|
+
|
|
48
|
+
def _memPrintIncrease(self, printOnlyOnGrowth=False):
|
|
49
|
+
gc.collect()
|
|
50
|
+
memNow = self._process.memory_info().rss
|
|
51
|
+
thisDiff = memNow - self._initialMem
|
|
52
|
+
lastDiff = self._lastMem - self._initialMem
|
|
53
|
+
growth = thisDiff - lastDiff
|
|
54
|
+
self._lastMem = memNow
|
|
55
|
+
if not printOnlyOnGrowth or growth:
|
|
56
|
+
print(
|
|
57
|
+
"Memory growth is %s, total growth %s, total %s"
|
|
58
|
+
% (
|
|
59
|
+
"{:,d}".format(growth),
|
|
60
|
+
"{:,d}".format(thisDiff),
|
|
61
|
+
"{:,d}".format(memNow),
|
|
62
|
+
)
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
def _memCheckFunction(self, callable, loopCount, *args, **kwargs):
|
|
66
|
+
assert loopCount >= 10, "We need at least 10 loops to check this"
|
|
67
|
+
# Give the memory 5 loops to warmed up, it shouldn't need more than 2
|
|
68
|
+
startMemIndex = 5
|
|
69
|
+
for index in range(loopCount):
|
|
70
|
+
if index == startMemIndex: # Mark the second loop only
|
|
71
|
+
self._memMark()
|
|
72
|
+
|
|
73
|
+
callable(*args, **kwargs)
|
|
74
|
+
|
|
75
|
+
if startMemIndex <= index:
|
|
76
|
+
self._memPrintIncrease(printOnlyOnGrowth=True)
|
|
77
|
+
|
|
78
|
+
self._memCheck(grace=0)
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
class VortexTcpConnectTestMixin:
|
|
82
|
+
@inlineCallbacks
|
|
83
|
+
def _connect(self):
|
|
84
|
+
port = 20000 + int(random() * 10000)
|
|
85
|
+
|
|
86
|
+
# Create the server
|
|
87
|
+
self._vortexServer = VortexServer("test server")
|
|
88
|
+
vortexTcpServerFactory = VortexTcpServerFactory(self._vortexServer)
|
|
89
|
+
self._listenPort = reactor.listenTCP(port, vortexTcpServerFactory)
|
|
90
|
+
|
|
91
|
+
# Create the client
|
|
92
|
+
self._vortexClient = VortexClientTcp("test client")
|
|
93
|
+
yield self._vortexClient.connect("127.0.0.1", port)
|
|
94
|
+
|
|
95
|
+
def _disconnect(self):
|
|
96
|
+
self._listenPort.stopListening()
|
|
97
|
+
del self._listenPort
|
|
98
|
+
|
|
99
|
+
self._vortexServer.shutdown()
|
|
100
|
+
del self._vortexServer
|
|
101
|
+
|
|
102
|
+
self._vortexClient.close()
|
|
103
|
+
del self._vortexClient
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class VortexSendReceiveTestMixin:
|
|
107
|
+
# Setup a queue state
|
|
108
|
+
_loopbackFilt = {"key": "unittest"}
|
|
109
|
+
|
|
110
|
+
class _State:
|
|
111
|
+
def __init__(self, testSelf, sendFromServerOnly):
|
|
112
|
+
self.testSelf = testSelf
|
|
113
|
+
self.sendFromServerOnly = sendFromServerOnly
|
|
114
|
+
|
|
115
|
+
self.dataSizeStats = []
|
|
116
|
+
self.vortexSizeStats = []
|
|
117
|
+
|
|
118
|
+
self.dataQueue = deque()
|
|
119
|
+
self.dataQueueEmptyDeferred = Deferred()
|
|
120
|
+
self.totalSent = 0
|
|
121
|
+
self.totalReceived = 0
|
|
122
|
+
self.totalMessagesSent = 0
|
|
123
|
+
self.totalMessagesReceived = 0
|
|
124
|
+
self.totalMessagesOutOfOrder = 0
|
|
125
|
+
self.highestOutOfOrderIndex = 0
|
|
126
|
+
|
|
127
|
+
self.totalSentFromClient = 0
|
|
128
|
+
self.totalSentFromServer = 0
|
|
129
|
+
|
|
130
|
+
def vortex(self, dataLen: int):
|
|
131
|
+
if not self.sendFromServerOnly and random() < 0.5:
|
|
132
|
+
self.totalSentFromClient += dataLen
|
|
133
|
+
return self.testSelf._vortexClient
|
|
134
|
+
|
|
135
|
+
self.totalSentFromServer += dataLen
|
|
136
|
+
return self.testSelf._vortexServer
|
|
137
|
+
|
|
138
|
+
class _Checker:
|
|
139
|
+
def __init__(self, testSelf, state, printStatusEveryXMessage):
|
|
140
|
+
self.endpoint = None
|
|
141
|
+
self.testSelf = testSelf
|
|
142
|
+
self.state = state
|
|
143
|
+
self.printStatusEveryXMessage = printStatusEveryXMessage
|
|
144
|
+
|
|
145
|
+
def setEndpoint(self, endpoint):
|
|
146
|
+
self.endpoint = endpoint
|
|
147
|
+
|
|
148
|
+
# Setup the receiver of the data
|
|
149
|
+
@inlineCallbacks
|
|
150
|
+
def process(self, payloadEnvelope, *args, **kwargs):
|
|
151
|
+
try:
|
|
152
|
+
payload = yield payloadEnvelope.decodePayloadDefer()
|
|
153
|
+
dataReceived = payload.tuples[0]
|
|
154
|
+
self.state.totalReceived += len(dataReceived)
|
|
155
|
+
self.state.totalMessagesReceived += 1
|
|
156
|
+
|
|
157
|
+
dataSent = None
|
|
158
|
+
for index, item in enumerate(self.state.dataQueue):
|
|
159
|
+
if item == dataReceived:
|
|
160
|
+
dataSent = dataReceived
|
|
161
|
+
if index:
|
|
162
|
+
self.state.totalMessagesOutOfOrder += 1
|
|
163
|
+
self.state.highestOutOfOrderIndex = max(
|
|
164
|
+
self.state.highestOutOfOrderIndex, index
|
|
165
|
+
)
|
|
166
|
+
self.state.dataQueue.remove(item)
|
|
167
|
+
|
|
168
|
+
else:
|
|
169
|
+
self.state.dataQueue.popleft()
|
|
170
|
+
|
|
171
|
+
break
|
|
172
|
+
|
|
173
|
+
if not (
|
|
174
|
+
self.state.totalMessagesReceived
|
|
175
|
+
% self.printStatusEveryXMessage
|
|
176
|
+
):
|
|
177
|
+
print(
|
|
178
|
+
"Received message %s, this %s, total %s"
|
|
179
|
+
% (
|
|
180
|
+
self.state.totalMessagesReceived,
|
|
181
|
+
"{:,d}".format(len(dataReceived)),
|
|
182
|
+
"{:,d}".format(self.state.totalReceived),
|
|
183
|
+
)
|
|
184
|
+
)
|
|
185
|
+
|
|
186
|
+
self.testSelf.assertEqual(dataReceived, dataSent)
|
|
187
|
+
|
|
188
|
+
if not self.state.dataQueue:
|
|
189
|
+
self.state.dataQueueEmptyDeferred.callback(True)
|
|
190
|
+
|
|
191
|
+
except Exception as e:
|
|
192
|
+
self.endpoint.shutdown()
|
|
193
|
+
self.state.dataQueueEmptyDeferred.errback(Failure(e))
|
|
194
|
+
|
|
195
|
+
@inlineCallbacks
|
|
196
|
+
def _vortexTestTcpServerClient(
|
|
197
|
+
self,
|
|
198
|
+
printStatusEveryXMessage: Optional[int] = 1000,
|
|
199
|
+
maxMessageSizeBytes: Optional[int] = None,
|
|
200
|
+
exactMessageSizeBytes: Optional[int] = None,
|
|
201
|
+
totalBytesToSend: Optional[int] = None,
|
|
202
|
+
totalMessagesToSend: Optional[int] = None,
|
|
203
|
+
payloadCompression=9,
|
|
204
|
+
sendFromServerOnly=False,
|
|
205
|
+
):
|
|
206
|
+
assert (
|
|
207
|
+
totalBytesToSend or totalMessagesToSend
|
|
208
|
+
), "We must have a total to send"
|
|
209
|
+
assert (
|
|
210
|
+
maxMessageSizeBytes or exactMessageSizeBytes
|
|
211
|
+
), "We must have a msg size"
|
|
212
|
+
|
|
213
|
+
state = self._State(self, sendFromServerOnly)
|
|
214
|
+
checker = self._Checker(self, state, printStatusEveryXMessage)
|
|
215
|
+
endpoint = PayloadEndpoint(self._loopbackFilt, checker.process)
|
|
216
|
+
checker.setEndpoint(endpoint)
|
|
217
|
+
|
|
218
|
+
# Make random chunks of data
|
|
219
|
+
def makeData():
|
|
220
|
+
size = (
|
|
221
|
+
random() * maxMessageSizeBytes
|
|
222
|
+
if exactMessageSizeBytes is None
|
|
223
|
+
else exactMessageSizeBytes
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
packet = str(random())
|
|
227
|
+
while len(packet) < size:
|
|
228
|
+
packet += str(random())
|
|
229
|
+
|
|
230
|
+
if exactMessageSizeBytes is not None:
|
|
231
|
+
packet = packet[:exactMessageSizeBytes]
|
|
232
|
+
|
|
233
|
+
return packet
|
|
234
|
+
|
|
235
|
+
def check():
|
|
236
|
+
if (
|
|
237
|
+
totalMessagesToSend
|
|
238
|
+
and state.totalMessagesSent < totalMessagesToSend
|
|
239
|
+
):
|
|
240
|
+
return True
|
|
241
|
+
|
|
242
|
+
if totalBytesToSend and state.totalSent < totalBytesToSend:
|
|
243
|
+
return True
|
|
244
|
+
|
|
245
|
+
return False
|
|
246
|
+
|
|
247
|
+
# Send the data
|
|
248
|
+
while check():
|
|
249
|
+
data = makeData()
|
|
250
|
+
state.dataQueue.append(data)
|
|
251
|
+
state.totalSent += len(data)
|
|
252
|
+
state.totalMessagesSent += 1
|
|
253
|
+
|
|
254
|
+
vortexMsg = yield Payload(
|
|
255
|
+
self._loopbackFilt, data
|
|
256
|
+
).makePayloadEnvelopeVortexMsgDefer(
|
|
257
|
+
compressionLevel=payloadCompression
|
|
258
|
+
)
|
|
259
|
+
|
|
260
|
+
state.dataSizeStats.append(len(data))
|
|
261
|
+
state.vortexSizeStats.append(len(vortexMsg))
|
|
262
|
+
|
|
263
|
+
# We could send this from either the vortexClient or vortexServer
|
|
264
|
+
# We only have one PayloadIO that the PayloadEndpoint binds to anyway
|
|
265
|
+
state.vortex(len(data)).sendVortexMsg(vortexMsg)
|
|
266
|
+
|
|
267
|
+
if not (state.totalMessagesSent % printStatusEveryXMessage):
|
|
268
|
+
print(
|
|
269
|
+
"Sent message %s, this %s, total %s"
|
|
270
|
+
% (
|
|
271
|
+
state.totalMessagesSent,
|
|
272
|
+
"{:,d}".format(len(data)),
|
|
273
|
+
"{:,d}".format(state.totalSent),
|
|
274
|
+
)
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
# Wait for all the sending to complete
|
|
278
|
+
yield state.dataQueueEmptyDeferred
|
|
279
|
+
|
|
280
|
+
print(
|
|
281
|
+
"%s messages were out of order, the most out of order was %s"
|
|
282
|
+
% (state.totalMessagesOutOfOrder, state.highestOutOfOrderIndex)
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
print(
|
|
286
|
+
"Sent %s from the vortex client"
|
|
287
|
+
% "{:,d}".format(state.totalSentFromClient)
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
print(
|
|
291
|
+
"Sent %s from the vortex server"
|
|
292
|
+
% "{:,d}".format(state.totalSentFromServer)
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
print(
|
|
296
|
+
"Data : count %s, total size %s, max size %s, min size %s, average %s"
|
|
297
|
+
% (
|
|
298
|
+
state.totalMessagesSent,
|
|
299
|
+
"{:,d}".format(state.totalSent),
|
|
300
|
+
"{:,d}".format(max(state.dataSizeStats)),
|
|
301
|
+
"{:,d}".format(min(state.dataSizeStats)),
|
|
302
|
+
"{:,d}".format(int(state.totalSent / state.totalMessagesSent)),
|
|
303
|
+
)
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
totalVortexMsgs = sum(state.vortexSizeStats)
|
|
307
|
+
print(
|
|
308
|
+
"VortexMsg: count %s, total size %s, max size %s, min size %s, average %s"
|
|
309
|
+
% (
|
|
310
|
+
state.totalMessagesSent,
|
|
311
|
+
"{:,d}".format(totalVortexMsgs),
|
|
312
|
+
"{:,d}".format(max(state.vortexSizeStats)),
|
|
313
|
+
"{:,d}".format(min(state.vortexSizeStats)),
|
|
314
|
+
"{:,d}".format(int(totalVortexMsgs / state.totalMessagesSent)),
|
|
315
|
+
)
|
|
316
|
+
)
|
|
317
|
+
|
|
318
|
+
# Run our checks
|
|
319
|
+
self.assertEqual(state.totalSent, state.totalReceived)
|
|
320
|
+
self.assertFalse(len(state.dataQueue))
|
|
321
|
+
|
|
322
|
+
# Cleanup
|
|
323
|
+
endpoint.shutdown()
|
|
324
|
+
del checker
|
|
325
|
+
del state
|
|
326
|
+
del endpoint
|
|
327
|
+
|
|
328
|
+
gc.collect()
|
|
329
|
+
|
|
330
|
+
|
|
331
|
+
class VortexTcpConnectTest(
|
|
332
|
+
unittest.TestCase,
|
|
333
|
+
MemoryCheckerTestMixin,
|
|
334
|
+
VortexTcpConnectTestMixin,
|
|
335
|
+
VortexSendReceiveTestMixin,
|
|
336
|
+
):
|
|
337
|
+
@inlineCallbacks
|
|
338
|
+
def __vortexReconnect(self, count):
|
|
339
|
+
self._memMark()
|
|
340
|
+
for x in range(count):
|
|
341
|
+
print("Reconnecting #%s" % x)
|
|
342
|
+
yield self._connect()
|
|
343
|
+
self._disconnect()
|
|
344
|
+
self._memPrintIncrease()
|
|
345
|
+
self._memPrintIncrease()
|
|
346
|
+
|
|
347
|
+
@inlineCallbacks
|
|
348
|
+
def test_vortexReconnect100(self):
|
|
349
|
+
yield self.__vortexReconnect(100)
|
|
350
|
+
|
|
351
|
+
@inlineCallbacks
|
|
352
|
+
def __vortexReconnect_with_data(self, count):
|
|
353
|
+
self._memMark()
|
|
354
|
+
for x in range(count):
|
|
355
|
+
print("Reconnecting #%s" % x)
|
|
356
|
+
yield self._connect()
|
|
357
|
+
yield self._vortexTestTcpServerClient(
|
|
358
|
+
totalMessagesToSend=10, exactMessageSizeBytes=100 * 1024
|
|
359
|
+
)
|
|
360
|
+
self._disconnect()
|
|
361
|
+
self._memPrintIncrease()
|
|
362
|
+
self._memPrintIncrease()
|
|
363
|
+
|
|
364
|
+
@inlineCallbacks
|
|
365
|
+
def test_vortexReconnect100_with_data(self):
|
|
366
|
+
yield self.__vortexReconnect_with_data(100)
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
class VortexTcpMemoryLeakTest(
|
|
370
|
+
unittest.TestCase,
|
|
371
|
+
MemoryCheckerTestMixin,
|
|
372
|
+
VortexTcpConnectTestMixin,
|
|
373
|
+
VortexSendReceiveTestMixin,
|
|
374
|
+
):
|
|
375
|
+
@inlineCallbacks
|
|
376
|
+
def __vortexSendMsgCountMsgSize(self, count, size, compression=9):
|
|
377
|
+
self._memMark()
|
|
378
|
+
yield self._connect()
|
|
379
|
+
yield self._vortexTestTcpServerClient(
|
|
380
|
+
totalMessagesToSend=count,
|
|
381
|
+
printStatusEveryXMessage=1000,
|
|
382
|
+
exactMessageSizeBytes=size,
|
|
383
|
+
payloadCompression=compression,
|
|
384
|
+
)
|
|
385
|
+
self._disconnect()
|
|
386
|
+
self._memPrintIncrease()
|
|
387
|
+
|
|
388
|
+
@inlineCallbacks
|
|
389
|
+
def test_1vortexSend1_1kb_compression1(self):
|
|
390
|
+
yield self.__vortexSendMsgCountMsgSize(1, 1 * 1024, 1)
|
|
391
|
+
|
|
392
|
+
@inlineCallbacks
|
|
393
|
+
def test_1vortexSend1_300kb_compression1(self):
|
|
394
|
+
yield self.__vortexSendMsgCountMsgSize(1, 300 * 1024, 1)
|
|
395
|
+
|
|
396
|
+
@inlineCallbacks
|
|
397
|
+
def test_1vortexSend10000_1kb_compression1(self):
|
|
398
|
+
yield self.__vortexSendMsgCountMsgSize(10000, 1 * 1024, 1)
|
|
399
|
+
|
|
400
|
+
@inlineCallbacks
|
|
401
|
+
def test_1vortexSend10000_100kb_compression1(self):
|
|
402
|
+
yield self.__vortexSendMsgCountMsgSize(10000, 100 * 1024, 1)
|
|
403
|
+
|
|
404
|
+
@inlineCallbacks
|
|
405
|
+
def test_1vortexSend10000_1kb_compression9(self):
|
|
406
|
+
yield self.__vortexSendMsgCountMsgSize(10000, 1 * 1024, 9)
|
|
407
|
+
|
|
408
|
+
@inlineCallbacks
|
|
409
|
+
def test_1vortexSend10000_100kb_compression9(self):
|
|
410
|
+
yield self.__vortexSendMsgCountMsgSize(10000, 100 * 1024, 9)
|
|
411
|
+
|
|
412
|
+
@inlineCallbacks
|
|
413
|
+
def __vortexSendTotalSendMsgSize(
|
|
414
|
+
self, totalSend, msgSize, compression=9, fromServer=False
|
|
415
|
+
):
|
|
416
|
+
self._memMark()
|
|
417
|
+
yield self._connect()
|
|
418
|
+
yield self._vortexTestTcpServerClient(
|
|
419
|
+
totalBytesToSend=totalSend,
|
|
420
|
+
printStatusEveryXMessage=1000,
|
|
421
|
+
maxMessageSizeBytes=msgSize,
|
|
422
|
+
sendFromServerOnly=fromServer,
|
|
423
|
+
payloadCompression=compression,
|
|
424
|
+
)
|
|
425
|
+
self._disconnect()
|
|
426
|
+
self._memPrintIncrease()
|
|
427
|
+
|
|
428
|
+
@inlineCallbacks
|
|
429
|
+
def test_2vortexSend1mb_1kb(self):
|
|
430
|
+
yield self.__vortexSendTotalSendMsgSize(1024 ** 2, 1 * 1024)
|
|
431
|
+
|
|
432
|
+
@inlineCallbacks
|
|
433
|
+
def test_2vortexSend1mb_100kb(self):
|
|
434
|
+
yield self.__vortexSendTotalSendMsgSize(1024 ** 2, 100 * 1024)
|
|
435
|
+
|
|
436
|
+
@inlineCallbacks
|
|
437
|
+
def test_3vortexSend1mb_X10_yes_reconnect(self):
|
|
438
|
+
mem = MemoryCheckerTestMixin()
|
|
439
|
+
mem._memMark()
|
|
440
|
+
|
|
441
|
+
print(" ===== START LOOP ===== ")
|
|
442
|
+
for i in range(10):
|
|
443
|
+
print(" ===== Running iteration %s ===== " % i)
|
|
444
|
+
self._memMark()
|
|
445
|
+
yield self._connect()
|
|
446
|
+
yield self._vortexTestTcpServerClient(
|
|
447
|
+
totalBytesToSend=1024 ** 2,
|
|
448
|
+
printStatusEveryXMessage=1000,
|
|
449
|
+
maxMessageSizeBytes=100 * 1024,
|
|
450
|
+
)
|
|
451
|
+
self._disconnect()
|
|
452
|
+
self._memPrintIncrease()
|
|
453
|
+
|
|
454
|
+
print(" ===== END LOOP ===== ")
|
|
455
|
+
mem._memPrintIncrease()
|
|
456
|
+
|
|
457
|
+
@inlineCallbacks
|
|
458
|
+
def test_3vortexSend1mb_X10_no_reconnect(self):
|
|
459
|
+
mem = MemoryCheckerTestMixin()
|
|
460
|
+
mem._memMark()
|
|
461
|
+
# Initialise the vortex
|
|
462
|
+
yield self._connect()
|
|
463
|
+
|
|
464
|
+
print(" ===== START LOOP ===== ")
|
|
465
|
+
for i in range(10):
|
|
466
|
+
print(" ===== Running iteration %s ===== " % i)
|
|
467
|
+
# Setup the parameters for the test
|
|
468
|
+
self._memMark()
|
|
469
|
+
yield self._vortexTestTcpServerClient(
|
|
470
|
+
totalBytesToSend=1024 ** 2,
|
|
471
|
+
printStatusEveryXMessage=1000,
|
|
472
|
+
maxMessageSizeBytes=1 * 1024,
|
|
473
|
+
)
|
|
474
|
+
self._memPrintIncrease()
|
|
475
|
+
|
|
476
|
+
self._disconnect()
|
|
477
|
+
print(" ===== END LOOP ===== ")
|
|
478
|
+
mem._memPrintIncrease()
|
|
479
|
+
|
|
480
|
+
@inlineCallbacks
|
|
481
|
+
def test_4vortexSend10mb(self):
|
|
482
|
+
yield self.__vortexSendTotalSendMsgSize(1024 ** 2 * 10, 100 * 1024)
|
|
483
|
+
|
|
484
|
+
@inlineCallbacks
|
|
485
|
+
def test_5vortexSend100mb(self):
|
|
486
|
+
yield self.__vortexSendTotalSendMsgSize(1024 ** 2 * 100, 1024 ** 2)
|
|
487
|
+
|
|
488
|
+
@inlineCallbacks
|
|
489
|
+
def test_6vortexSend500mb(self):
|
|
490
|
+
yield self.__vortexSendTotalSendMsgSize(1024 ** 2 * 500, 1024 ** 2)
|
|
491
|
+
|
|
492
|
+
|
|
493
|
+
class VortexTcpMemoryLeakLargeMessagesTest(
|
|
494
|
+
unittest.TestCase,
|
|
495
|
+
MemoryCheckerTestMixin,
|
|
496
|
+
VortexTcpConnectTestMixin,
|
|
497
|
+
VortexSendReceiveTestMixin,
|
|
498
|
+
):
|
|
499
|
+
# Increase the timeout to 15 minutes
|
|
500
|
+
timeout = 30 * 60
|
|
501
|
+
|
|
502
|
+
_patchedProcessData_dataReceivedLen = 0
|
|
503
|
+
|
|
504
|
+
def _processData_patch(self):
|
|
505
|
+
VortexTcpMemoryLeakLargeMessagesTest._patchedProcessData_dataReceivedLen += len(
|
|
506
|
+
self._data
|
|
507
|
+
)
|
|
508
|
+
|
|
509
|
+
# Just drop the data and continue
|
|
510
|
+
self._data = b""
|
|
511
|
+
|
|
512
|
+
@inlineCallbacks
|
|
513
|
+
def __vortexSend1g_oneway_maxmsg(self, msgSize, totalSize=1024 ** 2 * 500):
|
|
514
|
+
tracemalloc.start(5)
|
|
515
|
+
self._memMark()
|
|
516
|
+
yield self._connect()
|
|
517
|
+
yield self._vortexTestTcpServerClient(
|
|
518
|
+
totalBytesToSend=totalSize,
|
|
519
|
+
printStatusEveryXMessage=1000,
|
|
520
|
+
exactMessageSizeBytes=msgSize,
|
|
521
|
+
sendFromServerOnly=True,
|
|
522
|
+
payloadCompression=0,
|
|
523
|
+
)
|
|
524
|
+
|
|
525
|
+
self._disconnect()
|
|
526
|
+
|
|
527
|
+
snapshot = tracemalloc.take_snapshot()
|
|
528
|
+
top_stats = snapshot.statistics("lineno")
|
|
529
|
+
|
|
530
|
+
print("[ Top 10 ]")
|
|
531
|
+
for stat in top_stats[:10]:
|
|
532
|
+
print(stat)
|
|
533
|
+
|
|
534
|
+
tracemalloc.stop()
|
|
535
|
+
|
|
536
|
+
for _ in range(5):
|
|
537
|
+
d = Deferred()
|
|
538
|
+
reactor.callLater(2, d.callback, True)
|
|
539
|
+
print("Sleeping 2 seconds")
|
|
540
|
+
yield d
|
|
541
|
+
self._memPrintIncrease()
|
|
542
|
+
|
|
543
|
+
@inlineCallbacks
|
|
544
|
+
def test_1vortexSend50mb_oneway_msg10kb(self):
|
|
545
|
+
yield self.__vortexSend1g_oneway_maxmsg(
|
|
546
|
+
10 * 1024, totalSize=1024 ** 2 * 50
|
|
547
|
+
)
|
|
548
|
+
|
|
549
|
+
@inlineCallbacks
|
|
550
|
+
def test_1vortexSend50mb_oneway_msg100kb(self):
|
|
551
|
+
yield self.__vortexSend1g_oneway_maxmsg(
|
|
552
|
+
100 * 1024, totalSize=1024 ** 2 * 50
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
@inlineCallbacks
|
|
556
|
+
def test_1vortexSend50mb_oneway_msg1mb(self):
|
|
557
|
+
yield self.__vortexSend1g_oneway_maxmsg(
|
|
558
|
+
1 * 1024 ** 2, totalSize=1024 ** 2 * 50
|
|
559
|
+
)
|
|
560
|
+
|
|
561
|
+
@inlineCallbacks
|
|
562
|
+
def test_1vortexSend50mb_oneway_msg3mb(self):
|
|
563
|
+
yield self.__vortexSend1g_oneway_maxmsg(
|
|
564
|
+
3 * 1024 ** 2, totalSize=1024 ** 2 * 50
|
|
565
|
+
)
|
|
566
|
+
|
|
567
|
+
@inlineCallbacks
|
|
568
|
+
def test_1vortexSend50mb_oneway_msg10mb(self):
|
|
569
|
+
yield self.__vortexSend1g_oneway_maxmsg(
|
|
570
|
+
10 * 1024 ** 2, totalSize=1024 ** 2 * 50
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
@inlineCallbacks
|
|
574
|
+
def test_1vortexSend50mb_oneway_msg50mb(self):
|
|
575
|
+
yield self.__vortexSend1g_oneway_maxmsg(
|
|
576
|
+
50 * 1024 ** 2, totalSize=1024 ** 2 * 50
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
@inlineCallbacks
|
|
580
|
+
def test_1vortexSend500mb_oneway_msg10mb(self):
|
|
581
|
+
yield self.__vortexSend1g_oneway_maxmsg(
|
|
582
|
+
10 * 1024 ** 2, totalSize=500 * 1024 ** 2
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
class VortexTcpMemoryLeakLargeTransfersTest(
|
|
587
|
+
unittest.TestCase,
|
|
588
|
+
MemoryCheckerTestMixin,
|
|
589
|
+
VortexTcpConnectTestMixin,
|
|
590
|
+
VortexSendReceiveTestMixin,
|
|
591
|
+
):
|
|
592
|
+
@inlineCallbacks
|
|
593
|
+
def __vortexSendTest(self, total, compression):
|
|
594
|
+
self._memMark()
|
|
595
|
+
yield self._connect()
|
|
596
|
+
yield self._vortexTestTcpServerClient(
|
|
597
|
+
totalBytesToSend=total,
|
|
598
|
+
printStatusEveryXMessage=10000,
|
|
599
|
+
maxMessageSizeBytes=10 * 1024 ** 2,
|
|
600
|
+
payloadCompression=compression,
|
|
601
|
+
)
|
|
602
|
+
self._disconnect()
|
|
603
|
+
self._memPrintIncrease()
|
|
604
|
+
|
|
605
|
+
@inlineCallbacks
|
|
606
|
+
def test_2vortexSend1gb_compression1(self):
|
|
607
|
+
yield self.__vortexSendTest(1024 ** 3, compression=1)
|
|
608
|
+
|
|
609
|
+
@inlineCallbacks
|
|
610
|
+
def test_3vortexSend3gb_compression1(self):
|
|
611
|
+
yield self.__vortexSendTest(1024 ** 3 * 3, compression=1)
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"""
|
|
2
|
+
* Created by Synerty Pty Ltd
|
|
3
|
+
*
|
|
4
|
+
* This software is open source, the MIT license applies.
|
|
5
|
+
*
|
|
6
|
+
* Website : http://www.synerty.com
|
|
7
|
+
* Support : support@synerty.com
|
|
8
|
+
"""
|
|
9
|
+
import tracemalloc
|
|
10
|
+
|
|
11
|
+
from twisted.internet import reactor
|
|
12
|
+
from twisted.internet.defer import inlineCallbacks, Deferred
|
|
13
|
+
from twisted.trial import unittest
|
|
14
|
+
|
|
15
|
+
from vortex.VortexTcpMemoryLeakPayloadTest import (
|
|
16
|
+
MemoryCheckerTestMixin,
|
|
17
|
+
VortexTcpConnectTestMixin,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class VortexTcpMemoryLeakRawTest(
|
|
22
|
+
unittest.TestCase, MemoryCheckerTestMixin, VortexTcpConnectTestMixin
|
|
23
|
+
):
|
|
24
|
+
# Increase the timeout to 15 minutes
|
|
25
|
+
timeout = 30 * 60
|
|
26
|
+
|
|
27
|
+
_patchedProcessData_dataReceivedLen = 0
|
|
28
|
+
|
|
29
|
+
def _processData_patch(self):
|
|
30
|
+
VortexTcpMemoryLeakRawTest._patchedProcessData_dataReceivedLen += len(
|
|
31
|
+
self._data
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Just drop the data and continue
|
|
35
|
+
self._data = b""
|
|
36
|
+
|
|
37
|
+
@inlineCallbacks
|
|
38
|
+
def test_1vortexSend50mb_oneway_msg1mb_client_drop_data(self):
|
|
39
|
+
tracemalloc.start(5)
|
|
40
|
+
yield self._connect()
|
|
41
|
+
|
|
42
|
+
self._memMark()
|
|
43
|
+
|
|
44
|
+
from vortex.VortexPayloadProtocol import VortexPayloadProtocol
|
|
45
|
+
|
|
46
|
+
VortexPayloadProtocol._processData = (
|
|
47
|
+
VortexTcpMemoryLeakRawTest._processData_patch
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
dataSent = 0
|
|
51
|
+
for _ in range(1024):
|
|
52
|
+
dataSent += 1024**2
|
|
53
|
+
self._vortexServer.sendVortexMsg(b"x" * 1024**2)
|
|
54
|
+
|
|
55
|
+
# while dataSent < self._patchedProcessData_dataReceivedLen:
|
|
56
|
+
for _ in range(2):
|
|
57
|
+
print(
|
|
58
|
+
"Sleeping 2 seconds, send %s vs received %s"
|
|
59
|
+
% (dataSent, self._patchedProcessData_dataReceivedLen)
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
d = Deferred()
|
|
63
|
+
reactor.callLater(2, d.callback, True)
|
|
64
|
+
yield d
|
|
65
|
+
self._memPrintIncrease()
|
|
66
|
+
|
|
67
|
+
snapshot = tracemalloc.take_snapshot()
|
|
68
|
+
top_stats = snapshot.statistics("lineno")
|
|
69
|
+
|
|
70
|
+
print("[ Top 10 ]")
|
|
71
|
+
for stat in top_stats[:10]:
|
|
72
|
+
print(stat)
|
|
73
|
+
|
|
74
|
+
tracemalloc.stop()
|
|
75
|
+
|
|
76
|
+
# while dataSent < self._patchedProcessData_dataReceivedLen:
|
|
77
|
+
for _ in range(2):
|
|
78
|
+
print("Sleeping 2 seconds")
|
|
79
|
+
|
|
80
|
+
d = Deferred()
|
|
81
|
+
reactor.callLater(2, d.callback, True)
|
|
82
|
+
yield d
|
|
83
|
+
self._memPrintIncrease()
|
|
84
|
+
|
|
85
|
+
self._memPrintIncrease()
|
|
86
|
+
|
|
87
|
+
self._disconnect()
|