jetstream-api 0.17.0__tar.gz → 0.18.0__tar.gz
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.
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/PKG-INFO +1 -1
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/__init__.py +104 -104
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/admin.py +19 -10
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/common.py +40 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/connectivity.py +8 -1
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/partitioner.py +85 -78
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/producer.py +10 -7
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/properties.py +97 -9
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/qmgr.py +6 -4
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/jetstream_api.egg-info/PKG-INFO +1 -1
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/pyproject.toml +1 -1
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/LICENSE.txt +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/README.md +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/_codec.py +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/admintopic.py +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/exception.py +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/msg.py +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/pattern.py +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/py.typed +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/topic.py +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/ilink/util.py +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/jetstream_api.egg-info/SOURCES.txt +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/jetstream_api.egg-info/dependency_links.txt +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/jetstream_api.egg-info/requires.txt +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/jetstream_api.egg-info/top_level.txt +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/setup.cfg +0 -0
- {jetstream_api-0.17.0 → jetstream_api-0.18.0}/tests/test_example.py +0 -0
|
@@ -1,104 +1,104 @@
|
|
|
1
|
-
"""iLink - Python client API for iLink M.O.M. (Message Oriented Middleware)."""
|
|
2
|
-
|
|
3
|
-
__version__ = "0.
|
|
4
|
-
|
|
5
|
-
# --- Admin / Service ---
|
|
6
|
-
from .admin import ILAdminService, ILAdminQmgr, ILLogBrowser, ILQueueBrowser
|
|
7
|
-
|
|
8
|
-
# --- Queue Manager & Queue ---
|
|
9
|
-
from .qmgr import ILQmgr, ILQueue
|
|
10
|
-
|
|
11
|
-
# --- Message ---
|
|
12
|
-
from .msg import ILMsg, ILMsgUtil
|
|
13
|
-
|
|
14
|
-
# --- Constants & Enums ---
|
|
15
|
-
from .common import ILC, ILCC, ILRC, MatchOption
|
|
16
|
-
|
|
17
|
-
# --- Properties ---
|
|
18
|
-
from .properties import (
|
|
19
|
-
DestItem,
|
|
20
|
-
PartitionItem,
|
|
21
|
-
SegmentItem,
|
|
22
|
-
ILQueueProperty,
|
|
23
|
-
ILChannelProperty,
|
|
24
|
-
ILChannelType,
|
|
25
|
-
ILChannelStatus,
|
|
26
|
-
ILChannelDirection,
|
|
27
|
-
ILChannelSecurity,
|
|
28
|
-
ILChannelBalanceMode,
|
|
29
|
-
ILClusterNode,
|
|
30
|
-
ILClusterControlResult,
|
|
31
|
-
ILClusterProperty,
|
|
32
|
-
ILQmgrProperty,
|
|
33
|
-
ILSessionProperty,
|
|
34
|
-
ILServiceProperty,
|
|
35
|
-
ILSpokeProperty,
|
|
36
|
-
ILAccessRuleProperty,
|
|
37
|
-
ILSecureFileProperty,
|
|
38
|
-
ILQueueRealTimeInfo,
|
|
39
|
-
ILQueueFlow,
|
|
40
|
-
ILQmgrDiag,
|
|
41
|
-
ILClusterDefDiag,
|
|
42
|
-
ILClusterPeerDef,
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
# --- Exceptions ---
|
|
46
|
-
from .exception import (
|
|
47
|
-
ILException,
|
|
48
|
-
ILNoMsgException,
|
|
49
|
-
ILTimeoutException,
|
|
50
|
-
ILOperationException,
|
|
51
|
-
ILSessionException,
|
|
52
|
-
ILMsgTypeException,
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
__all__ = [
|
|
56
|
-
# Admin
|
|
57
|
-
"ILAdminService",
|
|
58
|
-
"ILAdminQmgr",
|
|
59
|
-
"ILLogBrowser",
|
|
60
|
-
"ILQueueBrowser",
|
|
61
|
-
# QMgr / Queue
|
|
62
|
-
"ILQmgr",
|
|
63
|
-
"ILQueue",
|
|
64
|
-
# Message
|
|
65
|
-
"ILMsg",
|
|
66
|
-
"ILMsgUtil",
|
|
67
|
-
# Constants
|
|
68
|
-
"ILC",
|
|
69
|
-
"ILCC",
|
|
70
|
-
"ILRC",
|
|
71
|
-
"MatchOption",
|
|
72
|
-
# Properties
|
|
73
|
-
"DestItem",
|
|
74
|
-
"PartitionItem",
|
|
75
|
-
"SegmentItem",
|
|
76
|
-
"ILQueueProperty",
|
|
77
|
-
"ILChannelProperty",
|
|
78
|
-
"ILChannelType",
|
|
79
|
-
"ILChannelStatus",
|
|
80
|
-
"ILChannelDirection",
|
|
81
|
-
"ILChannelSecurity",
|
|
82
|
-
"ILChannelBalanceMode",
|
|
83
|
-
"ILClusterNode",
|
|
84
|
-
"ILClusterControlResult",
|
|
85
|
-
"ILClusterProperty",
|
|
86
|
-
"ILQmgrProperty",
|
|
87
|
-
"ILSessionProperty",
|
|
88
|
-
"ILServiceProperty",
|
|
89
|
-
"ILSpokeProperty",
|
|
90
|
-
"ILAccessRuleProperty",
|
|
91
|
-
"ILSecureFileProperty",
|
|
92
|
-
"ILQueueRealTimeInfo",
|
|
93
|
-
"ILQueueFlow",
|
|
94
|
-
"ILQmgrDiag",
|
|
95
|
-
"ILClusterDefDiag",
|
|
96
|
-
"ILClusterPeerDef",
|
|
97
|
-
# Exceptions
|
|
98
|
-
"ILException",
|
|
99
|
-
"ILNoMsgException",
|
|
100
|
-
"ILTimeoutException",
|
|
101
|
-
"ILOperationException",
|
|
102
|
-
"ILSessionException",
|
|
103
|
-
"ILMsgTypeException",
|
|
104
|
-
]
|
|
1
|
+
"""iLink - Python client API for iLink M.O.M. (Message Oriented Middleware)."""
|
|
2
|
+
|
|
3
|
+
__version__ = "0.18.0"
|
|
4
|
+
|
|
5
|
+
# --- Admin / Service ---
|
|
6
|
+
from .admin import ILAdminService, ILAdminQmgr, ILLogBrowser, ILQueueBrowser
|
|
7
|
+
|
|
8
|
+
# --- Queue Manager & Queue ---
|
|
9
|
+
from .qmgr import ILQmgr, ILQueue
|
|
10
|
+
|
|
11
|
+
# --- Message ---
|
|
12
|
+
from .msg import ILMsg, ILMsgUtil
|
|
13
|
+
|
|
14
|
+
# --- Constants & Enums ---
|
|
15
|
+
from .common import ILC, ILCC, ILRC, MatchOption
|
|
16
|
+
|
|
17
|
+
# --- Properties ---
|
|
18
|
+
from .properties import (
|
|
19
|
+
DestItem,
|
|
20
|
+
PartitionItem,
|
|
21
|
+
SegmentItem,
|
|
22
|
+
ILQueueProperty,
|
|
23
|
+
ILChannelProperty,
|
|
24
|
+
ILChannelType,
|
|
25
|
+
ILChannelStatus,
|
|
26
|
+
ILChannelDirection,
|
|
27
|
+
ILChannelSecurity,
|
|
28
|
+
ILChannelBalanceMode,
|
|
29
|
+
ILClusterNode,
|
|
30
|
+
ILClusterControlResult,
|
|
31
|
+
ILClusterProperty,
|
|
32
|
+
ILQmgrProperty,
|
|
33
|
+
ILSessionProperty,
|
|
34
|
+
ILServiceProperty,
|
|
35
|
+
ILSpokeProperty,
|
|
36
|
+
ILAccessRuleProperty,
|
|
37
|
+
ILSecureFileProperty,
|
|
38
|
+
ILQueueRealTimeInfo,
|
|
39
|
+
ILQueueFlow,
|
|
40
|
+
ILQmgrDiag,
|
|
41
|
+
ILClusterDefDiag,
|
|
42
|
+
ILClusterPeerDef,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# --- Exceptions ---
|
|
46
|
+
from .exception import (
|
|
47
|
+
ILException,
|
|
48
|
+
ILNoMsgException,
|
|
49
|
+
ILTimeoutException,
|
|
50
|
+
ILOperationException,
|
|
51
|
+
ILSessionException,
|
|
52
|
+
ILMsgTypeException,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
__all__ = [
|
|
56
|
+
# Admin
|
|
57
|
+
"ILAdminService",
|
|
58
|
+
"ILAdminQmgr",
|
|
59
|
+
"ILLogBrowser",
|
|
60
|
+
"ILQueueBrowser",
|
|
61
|
+
# QMgr / Queue
|
|
62
|
+
"ILQmgr",
|
|
63
|
+
"ILQueue",
|
|
64
|
+
# Message
|
|
65
|
+
"ILMsg",
|
|
66
|
+
"ILMsgUtil",
|
|
67
|
+
# Constants
|
|
68
|
+
"ILC",
|
|
69
|
+
"ILCC",
|
|
70
|
+
"ILRC",
|
|
71
|
+
"MatchOption",
|
|
72
|
+
# Properties
|
|
73
|
+
"DestItem",
|
|
74
|
+
"PartitionItem",
|
|
75
|
+
"SegmentItem",
|
|
76
|
+
"ILQueueProperty",
|
|
77
|
+
"ILChannelProperty",
|
|
78
|
+
"ILChannelType",
|
|
79
|
+
"ILChannelStatus",
|
|
80
|
+
"ILChannelDirection",
|
|
81
|
+
"ILChannelSecurity",
|
|
82
|
+
"ILChannelBalanceMode",
|
|
83
|
+
"ILClusterNode",
|
|
84
|
+
"ILClusterControlResult",
|
|
85
|
+
"ILClusterProperty",
|
|
86
|
+
"ILQmgrProperty",
|
|
87
|
+
"ILSessionProperty",
|
|
88
|
+
"ILServiceProperty",
|
|
89
|
+
"ILSpokeProperty",
|
|
90
|
+
"ILAccessRuleProperty",
|
|
91
|
+
"ILSecureFileProperty",
|
|
92
|
+
"ILQueueRealTimeInfo",
|
|
93
|
+
"ILQueueFlow",
|
|
94
|
+
"ILQmgrDiag",
|
|
95
|
+
"ILClusterDefDiag",
|
|
96
|
+
"ILClusterPeerDef",
|
|
97
|
+
# Exceptions
|
|
98
|
+
"ILException",
|
|
99
|
+
"ILNoMsgException",
|
|
100
|
+
"ILTimeoutException",
|
|
101
|
+
"ILOperationException",
|
|
102
|
+
"ILSessionException",
|
|
103
|
+
"ILMsgTypeException",
|
|
104
|
+
]
|
|
@@ -119,7 +119,7 @@ class ILAdminService:
|
|
|
119
119
|
args (list[str]): 명령행 인자. ``["--version"]`` 이면 버전을 찍는다.
|
|
120
120
|
"""
|
|
121
121
|
if len(args) != 1:
|
|
122
|
-
print("available
|
|
122
|
+
print("available arguments.")
|
|
123
123
|
print(" --version : displays the library version.")
|
|
124
124
|
ILC.print_version(args[0] if args else "")
|
|
125
125
|
|
|
@@ -170,9 +170,11 @@ class ILAdminService:
|
|
|
170
170
|
self.service.connect(host, port)
|
|
171
171
|
if not clientName:
|
|
172
172
|
clientName = caller_module_name() # 0.11.0: inspect.stack()[-1] 과 같은 값(프레임 순회 - 소스 줄을 읽지 않는다)
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
)
|
|
173
|
+
# 0.18.0: 능력 선언을 **확장**에 싣는다. ☠ arg1 은 자동커밋 플래그 자리다.
|
|
174
|
+
_caps = ILC.client_caps_extension()
|
|
175
|
+
_cargs = ((ILC.MIMQ_NEW_CONNECTION,) + ((_caps,) if _caps else ())
|
|
176
|
+
+ ("0", clientName, "USR"))
|
|
177
|
+
conn_res_msg = self.service.request(*_cargs)
|
|
176
178
|
if conn_res_msg is None:
|
|
177
179
|
raise ILOperationException("MIMQE_INTERNAL_ERROR")
|
|
178
180
|
if conn_res_msg.getCode() != ILC.MIMQ_SUCCESSFUL_CONNECTION:
|
|
@@ -1035,6 +1037,7 @@ class ILAdminService:
|
|
|
1035
1037
|
if not isinstance(cluster, ILClusterProperty):
|
|
1036
1038
|
raise ILOperationException(
|
|
1037
1039
|
"MIMQE_INVALID_ARGUMENT (createCluster takes an ILClusterProperty)")
|
|
1040
|
+
cluster._validate_addresses() # 왕복 전에 막는다 - 사유가 빠르다
|
|
1038
1041
|
self.service.apply_for_report(
|
|
1039
1042
|
ILC.MIMQ_CREATE_CLUSTER,
|
|
1040
1043
|
cluster.get_serialized(),
|
|
@@ -1178,6 +1181,11 @@ class ILAdminService:
|
|
|
1178
1181
|
Note:
|
|
1179
1182
|
**노드 목록은 바꿀 수 없다** - 다르면 거절된다(조용히 무시되지 않는다).
|
|
1180
1183
|
|
|
1184
|
+
Note:
|
|
1185
|
+
★ **컨트롤러는 서비스마다 하나다.** 컨트롤러를 셋 두려면 관리 서비스가
|
|
1186
|
+
셋 있어야 한다 - 한 서비스에 몰면 나머지는 **닿지 않는 피어**가 되어
|
|
1187
|
+
과반을 못 채우고 ☠ **거절이 아니라 끝나지 않는다.**
|
|
1188
|
+
|
|
1181
1189
|
Example::
|
|
1182
1190
|
|
|
1183
1191
|
p = judge_svc.getClusterProperty("C1")
|
|
@@ -1186,6 +1194,7 @@ class ILAdminService:
|
|
|
1186
1194
|
"""
|
|
1187
1195
|
try:
|
|
1188
1196
|
self._checkClusterSupported()
|
|
1197
|
+
cluster._validate_addresses()
|
|
1189
1198
|
self.service.apply_for_report(
|
|
1190
1199
|
ILC.MIMQ_SET_CLUSTER_PROPERTY,
|
|
1191
1200
|
cluster.get_serialized(),
|
|
@@ -2865,7 +2874,7 @@ class ILAdminQmgr:
|
|
|
2865
2874
|
args (list[str]): 명령행 인자. ``["--version"]`` 이면 버전을 찍는다.
|
|
2866
2875
|
"""
|
|
2867
2876
|
if len(args) != 1:
|
|
2868
|
-
print("available
|
|
2877
|
+
print("available arguments.")
|
|
2869
2878
|
print(" --version : displays the library version.")
|
|
2870
2879
|
ILC.print_version(args[0] if args else "")
|
|
2871
2880
|
|
|
@@ -5666,12 +5675,12 @@ class ILAdminQmgr:
|
|
|
5666
5675
|
전부다). 그래서 **클라이언트가 막는다** - 안 막으면 ``"JSON"``
|
|
5667
5676
|
이나 오타를 보낸 쪽이 **요청한 것과 다른 모양을 조용히 받는다.**
|
|
5668
5677
|
|
|
5669
|
-
Raises:
|
|
5670
|
-
ValueError: ``format`` 이 ``"TEXT"`` / ``"LINE"`` 이 아닐 때.
|
|
5671
|
-
|
|
5672
5678
|
Returns:
|
|
5673
5679
|
리포트 문자열. 클러스터 미구성이면 본문에 ``STANDALONE (not clustered)``.
|
|
5674
5680
|
|
|
5681
|
+
Raises:
|
|
5682
|
+
ValueError: ``format`` 이 ``"TEXT"`` / ``"LINE"`` 이 아닐 때.
|
|
5683
|
+
|
|
5675
5684
|
Example::
|
|
5676
5685
|
|
|
5677
5686
|
aq = svc.accessAdminQmgr("NODE_A")
|
|
@@ -6134,8 +6143,8 @@ class ILAdminQmgr:
|
|
|
6134
6143
|
|
|
6135
6144
|
Args:
|
|
6136
6145
|
topicName (str): 토픽 이름. 엔진 **rev 3393 이상**은 ``A-Z a-z 0-9 . _ -``
|
|
6137
|
-
만 1~47바이트로 받고 ``.`` / ``..`` 는
|
|
6138
|
-
|
|
6146
|
+
만 1~47바이트로 받고 ``.`` / ``..`` 는 거절한다.
|
|
6147
|
+
그 이전 엔진은 47바이트 상한만 검사한다. 엔진은 **생성할 때만**
|
|
6139
6148
|
검사하므로 이미 있는 토픽은 이름과 상관없이 계속 쓸 수 있다.
|
|
6140
6149
|
options (str): ``key=value`` 를 ``;`` 로 이은 문자열. 기본 ``""`` 는
|
|
6141
6150
|
엔진 기본값이다. 예 ``"partitions=3"``, ``"retentionms=86400000"``.
|
|
@@ -895,6 +895,17 @@ class ILC:
|
|
|
895
895
|
MIMQ_CLIENT_NAME_ILSC = "ILSC"
|
|
896
896
|
MIMQ_CLIENT_NAME_ILSVC = "ILSVC"
|
|
897
897
|
MIMQ_CLIENT_NAME_ILWC = "ILWC"
|
|
898
|
+
|
|
899
|
+
#: 접속 확장에 싣는 **능력 선언**의 접두(0.18.0, 엔진 CAPDECL-2 짝).
|
|
900
|
+
#: ☠ ``arg1`` 에 실으면 안 된다 - 엔진이 그 자리를 **자동커밋 플래그**로 읽는다
|
|
901
|
+
#: (``atoi("0.18.0") == 0`` 이라 모든 세션이 조용히 트랜잭션 모드가 된다).
|
|
902
|
+
MIMQ_CLIENT_CAPS_PREFIX = "CAP="
|
|
903
|
+
#: 능력 선언의 최대 길이(접두 포함). 넘으면 **자르지 않고 통째로 버린다** -
|
|
904
|
+
#: 자르면 ``clsblob=2`` 가 ``clsblob=`` 가 되어 **읽히는데 뜻이 다른** 값이 된다.
|
|
905
|
+
MIMQ_CLIENT_CAPS_MAX = 63
|
|
906
|
+
#: 이 클라가 읽고 쓰는 클러스터 블롭 판. :data:`ilink.properties.CLUSTER_LAYOUT_MARK`
|
|
907
|
+
#: 와 능력 선언이 **모두 이 값에서 나온다** - 판 번호를 두 곳에 적지 않는다.
|
|
908
|
+
MIMQ_CLUSTER_BLOB_VERSION = 2
|
|
898
909
|
MIMQ_SESSION_STATUS_DEAD = 0
|
|
899
910
|
MIMQ_SESSION_STATUS_IDLE = 1
|
|
900
911
|
MIMQ_SESSION_STATUS_RECEIVING = 2
|
|
@@ -1027,6 +1038,35 @@ class ILC:
|
|
|
1027
1038
|
return False
|
|
1028
1039
|
return True
|
|
1029
1040
|
|
|
1041
|
+
@staticmethod
|
|
1042
|
+
def client_caps_extension():
|
|
1043
|
+
"""접속 메시지에 실을 **능력 선언** 확장을 만든다(0.18.0).
|
|
1044
|
+
|
|
1045
|
+
Returns:
|
|
1046
|
+
bytes | None: ``b"CAP=clsblob=2,ver=0.18.0"`` 꼴. 길이가
|
|
1047
|
+
:data:`MIMQ_CLIENT_CAPS_MAX` 를 넘으면 **None**(안 싣는다).
|
|
1048
|
+
|
|
1049
|
+
Note:
|
|
1050
|
+
★ 엔진은 이 값을 **기록만** 한다 - 아무것도 거부하지 않는다. 이득은
|
|
1051
|
+
**다음 판 변경 때부터**다: 그때 엔진이 "못 읽는 클라" 에게 사유 있는
|
|
1052
|
+
오류를 줄 수 있다. 지금 배포된 판(0.17.0 이하)은 구할 수 없다.
|
|
1053
|
+
|
|
1054
|
+
☠ **admin / qmgr 유형에만 싣는다.** ``CHL`` / ``REL`` 은 확장을 자기
|
|
1055
|
+
용도로 쓰고 옛 엔진이 그 크기로 분기한다.
|
|
1056
|
+
|
|
1057
|
+
판정은 ``clsblob`` 으로 한다. ``ver`` 은 사람이 로그에서 읽는 값이고
|
|
1058
|
+
**판정에 쓰지 않는다** - 판 문자열로 능력을 유도하면 엔진이 표를 들고
|
|
1059
|
+
있어야 하고 그 표는 반드시 낡는다.
|
|
1060
|
+
"""
|
|
1061
|
+
import ilink # 판 문자열은 한 곳에만 있다
|
|
1062
|
+
text = "%sclsblob=%d,ver=%s" % (ILC.MIMQ_CLIENT_CAPS_PREFIX,
|
|
1063
|
+
ILC.MIMQ_CLUSTER_BLOB_VERSION,
|
|
1064
|
+
getattr(ilink, "__version__", "?"))
|
|
1065
|
+
raw = bytes(c for c in text.encode("utf-8", "replace") if 0x20 <= c <= 0x7E)
|
|
1066
|
+
if len(raw) > ILC.MIMQ_CLIENT_CAPS_MAX:
|
|
1067
|
+
return None # 자르지 않는다 - 뜻이 달라진다
|
|
1068
|
+
return raw
|
|
1069
|
+
|
|
1030
1070
|
@staticmethod
|
|
1031
1071
|
def get_api_version_info() -> str:
|
|
1032
1072
|
"""이 라이브러리의 버전 정보 문자열.
|
|
@@ -42,7 +42,14 @@ def _ba_pick_int(ba: bytes, offset: int, length: int) -> int:
|
|
|
42
42
|
|
|
43
43
|
|
|
44
44
|
def clamp_max_frame_length(n: int) -> int:
|
|
45
|
-
"""프레임 길이 상한 설정값을 엔진 설정 범위(1,048,576 ~ 999,999,999)로 맞춘다.
|
|
45
|
+
"""프레임 길이 상한 설정값을 엔진 설정 범위(1,048,576 ~ 999,999,999)로 맞춘다.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
n (int): 맞출 값(**바이트**).
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
int: 범위 안으로 보정한 값(**바이트**).
|
|
52
|
+
"""
|
|
46
53
|
return min(max(ILC.MIMQ_MIN_MAX_FRAME_LENGTH, int(n)), ILC.MIMQ_MAX_FRAME_LENGTH)
|
|
47
54
|
|
|
48
55
|
|
|
@@ -1,78 +1,85 @@
|
|
|
1
|
-
"""토픽 파티셔너 - 키로 파티션 번호를 정한다(Kafka ``DefaultPartitioner`` 와 같은 규칙).
|
|
2
|
-
|
|
3
|
-
엔진은 발행 레코드의 파티션을 고르지 않는다(IDEMP 설계 v0.4, 사용자 결정). 발행 경로
|
|
4
|
-
(producer, 관리 API 단건 발행)가 **이 모듈 하나로** 파티션을 정해 명시 파티션으로 싣는다.
|
|
5
|
-
그래서 같은 키는 어느 경로로 보내도 같은 파티션으로 간다.
|
|
6
|
-
|
|
7
|
-
- 해시는 Kafka ``org.apache.kafka.common.utils.Utils.murmur2`` 와 비트 단위로 같다
|
|
8
|
-
(seed ``0x9747b28c``). 골든 벡터 ``tests/data/murmur2_golden.txt`` 는 Kafka 3.9 jar 에서 뽑았다.
|
|
9
|
-
- 키는 **UTF-8 바이트**로 해시한다. 자바 클라이언트도 같은 바이트를 쓴다.
|
|
10
|
-
- 파티션 = ``to_positive(murmur2(UTF-8 키)) % 파티션 수``.
|
|
11
|
-
|
|
12
|
-
**응용이 직접 부를 일은 없다** - 라이브러리 내부에서 쓴다.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
from __future__ import annotations
|
|
16
|
-
|
|
17
|
-
_M = 0x5BD1E995
|
|
18
|
-
_SEED = 0x9747B28C
|
|
19
|
-
_MASK = 0xFFFFFFFF
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
def murmur2(data: bytes) -> int:
|
|
23
|
-
"""Kafka ``Utils.murmur2`` 와 같은 32비트 해시(부호 있는 정수)를 돌려준다.
|
|
24
|
-
|
|
25
|
-
Args:
|
|
26
|
-
data (bytes): 해시할 바이트.
|
|
27
|
-
|
|
28
|
-
Returns:
|
|
29
|
-
int: -2^31 ~ 2^31-1 범위의 해시(자바 int 와 같은 값).
|
|
30
|
-
"""
|
|
31
|
-
length = len(data)
|
|
32
|
-
h = (_SEED ^ length) & _MASK
|
|
33
|
-
n4 = length // 4
|
|
34
|
-
for i in range(n4):
|
|
35
|
-
i4 = i * 4
|
|
36
|
-
k = data[i4] | (data[i4 + 1] << 8) | (data[i4 + 2] << 16) | (data[i4 + 3] << 24)
|
|
37
|
-
k = (k * _M) & _MASK
|
|
38
|
-
k ^= k >> 24
|
|
39
|
-
k = (k * _M) & _MASK
|
|
40
|
-
h = (h * _M) & _MASK
|
|
41
|
-
h ^= k
|
|
42
|
-
rem = length % 4
|
|
43
|
-
base = length & ~3
|
|
44
|
-
if rem >= 3:
|
|
45
|
-
h ^= data[base + 2] << 16
|
|
46
|
-
if rem >= 2:
|
|
47
|
-
h ^= data[base + 1] << 8
|
|
48
|
-
if rem >= 1:
|
|
49
|
-
h ^= data[base]
|
|
50
|
-
h = (h * _M) & _MASK
|
|
51
|
-
h ^= h >> 13
|
|
52
|
-
h = (h * _M) & _MASK
|
|
53
|
-
h ^= h >> 15
|
|
54
|
-
return h - (1 << 32) if h & 0x80000000 else h
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
def to_positive(value: int) -> int:
|
|
58
|
-
"""Kafka ``Utils.toPositive`` - 부호 비트를 떼어 0 이상으로 만든다.
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
1
|
+
"""토픽 파티셔너 - 키로 파티션 번호를 정한다(Kafka ``DefaultPartitioner`` 와 같은 규칙).
|
|
2
|
+
|
|
3
|
+
엔진은 발행 레코드의 파티션을 고르지 않는다(IDEMP 설계 v0.4, 사용자 결정). 발행 경로
|
|
4
|
+
(producer, 관리 API 단건 발행)가 **이 모듈 하나로** 파티션을 정해 명시 파티션으로 싣는다.
|
|
5
|
+
그래서 같은 키는 어느 경로로 보내도 같은 파티션으로 간다.
|
|
6
|
+
|
|
7
|
+
- 해시는 Kafka ``org.apache.kafka.common.utils.Utils.murmur2`` 와 비트 단위로 같다
|
|
8
|
+
(seed ``0x9747b28c``). 골든 벡터 ``tests/data/murmur2_golden.txt`` 는 Kafka 3.9 jar 에서 뽑았다.
|
|
9
|
+
- 키는 **UTF-8 바이트**로 해시한다. 자바 클라이언트도 같은 바이트를 쓴다.
|
|
10
|
+
- 파티션 = ``to_positive(murmur2(UTF-8 키)) % 파티션 수``.
|
|
11
|
+
|
|
12
|
+
**응용이 직접 부를 일은 없다** - 라이브러리 내부에서 쓴다.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
_M = 0x5BD1E995
|
|
18
|
+
_SEED = 0x9747B28C
|
|
19
|
+
_MASK = 0xFFFFFFFF
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def murmur2(data: bytes) -> int:
|
|
23
|
+
"""Kafka ``Utils.murmur2`` 와 같은 32비트 해시(부호 있는 정수)를 돌려준다.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
data (bytes): 해시할 바이트.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
int: -2^31 ~ 2^31-1 범위의 해시(자바 int 와 같은 값).
|
|
30
|
+
"""
|
|
31
|
+
length = len(data)
|
|
32
|
+
h = (_SEED ^ length) & _MASK
|
|
33
|
+
n4 = length // 4
|
|
34
|
+
for i in range(n4):
|
|
35
|
+
i4 = i * 4
|
|
36
|
+
k = data[i4] | (data[i4 + 1] << 8) | (data[i4 + 2] << 16) | (data[i4 + 3] << 24)
|
|
37
|
+
k = (k * _M) & _MASK
|
|
38
|
+
k ^= k >> 24
|
|
39
|
+
k = (k * _M) & _MASK
|
|
40
|
+
h = (h * _M) & _MASK
|
|
41
|
+
h ^= k
|
|
42
|
+
rem = length % 4
|
|
43
|
+
base = length & ~3
|
|
44
|
+
if rem >= 3:
|
|
45
|
+
h ^= data[base + 2] << 16
|
|
46
|
+
if rem >= 2:
|
|
47
|
+
h ^= data[base + 1] << 8
|
|
48
|
+
if rem >= 1:
|
|
49
|
+
h ^= data[base]
|
|
50
|
+
h = (h * _M) & _MASK
|
|
51
|
+
h ^= h >> 13
|
|
52
|
+
h = (h * _M) & _MASK
|
|
53
|
+
h ^= h >> 15
|
|
54
|
+
return h - (1 << 32) if h & 0x80000000 else h
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def to_positive(value: int) -> int:
|
|
58
|
+
"""Kafka ``Utils.toPositive`` - 부호 비트를 떼어 0 이상으로 만든다.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
value (int): 부호 있는 32비트 값.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
int: 0 이상으로 만든 값.
|
|
65
|
+
"""
|
|
66
|
+
return value & 0x7FFFFFFF
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def partition_for_key(key: str | bytes, num_partitions: int) -> int:
|
|
70
|
+
"""키가 있는 레코드의 파티션 번호.
|
|
71
|
+
|
|
72
|
+
Args:
|
|
73
|
+
key (str | bytes): 레코드 키. 문자열이면 UTF-8 로 바꿔 해시한다.
|
|
74
|
+
num_partitions (int): 토픽의 파티션 수(1 이상).
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
int: 0 ~ num_partitions-1.
|
|
78
|
+
|
|
79
|
+
Raises:
|
|
80
|
+
ValueError: 파티션 수가 1 미만일 때.
|
|
81
|
+
"""
|
|
82
|
+
if num_partitions < 1:
|
|
83
|
+
raise ValueError("num_partitions must be >= 1: %r" % (num_partitions,))
|
|
84
|
+
raw = key.encode("utf-8") if isinstance(key, str) else bytes(key)
|
|
85
|
+
return to_positive(murmur2(raw)) % num_partitions
|
|
@@ -303,7 +303,7 @@ class ILProducerConfig:
|
|
|
303
303
|
|
|
304
304
|
def maxRequestSize(self, n: int) -> "ILProducerConfig":
|
|
305
305
|
"""**봉투 하나의 본문 크기 상한**이자 레코드 크기 상한(바이트).
|
|
306
|
-
(기본 1048576 = 1MB
|
|
306
|
+
(기본 1048576 = 1MB)
|
|
307
307
|
|
|
308
308
|
Args:
|
|
309
309
|
n (int): 프레임 크기 상한(**바이트**). **1024 미만은 1024 로, 999,999,974 초과는
|
|
@@ -417,7 +417,7 @@ class ILProducerConfig:
|
|
|
417
417
|
"""lz4 압축 레벨을 정한다. (기본 ``9`` = 빠른 압축기)
|
|
418
418
|
|
|
419
419
|
Args:
|
|
420
|
-
level (int): ``1`` ~ ``17``.
|
|
420
|
+
level (int): ``1`` ~ ``17``. ``9`` (기본)는 빠른 압축기이고,
|
|
421
421
|
``9`` 가 아닌 값은 그 레벨의 LZ4HC(훨씬 느리고 조금 더 준다)다. 레벨 12 이상은 결과가 같다.
|
|
422
422
|
|
|
423
423
|
Returns:
|
|
@@ -689,8 +689,8 @@ class ILProducerConfig:
|
|
|
689
689
|
# 0.7.0: 엔진은 (pid, 파티션)마다 최근 배치 5개로 중복을 가린다 - 그보다 많이 겹쳐 보내면 재전송이 중복으로 가려지지 않는다
|
|
690
690
|
if self._idempotenceSet and self._enableIdempotence and self._maxInFlight > 5:
|
|
691
691
|
raise ValueError(
|
|
692
|
-
"enableIdempotence requires maxInFlight <= 5
|
|
693
|
-
"
|
|
692
|
+
"enableIdempotence requires maxInFlight <= 5"
|
|
693
|
+
" (the engine remembers the last 5 batches per partition)"
|
|
694
694
|
)
|
|
695
695
|
# 0.8.0: 직접 대입(cfg.compressionType = "gzip")은 빌더의 검사를 거치지 않는다 - 여기서 다시 본다
|
|
696
696
|
self._compressionType = _codec.check_type(self._compressionType)
|
|
@@ -1492,7 +1492,9 @@ class ILTopicProducer:
|
|
|
1492
1492
|
conn.max_frame_length = self.config.get_max_frame_length()
|
|
1493
1493
|
conn.connect(host, port, self.config.get_request_timeout_ms())
|
|
1494
1494
|
try:
|
|
1495
|
-
|
|
1495
|
+
# 0.18.0: 능력 선언. ☠ arg1("1")은 자동커밋 플래그라 그대로 둔다.
|
|
1496
|
+
rep = self._request(conn, ILC.MIMQ_NEW_CONNECTION, "1", self.clientName, "USR",
|
|
1497
|
+
ext=ILC.client_caps_extension())
|
|
1496
1498
|
if rep is None or rep.getCode() != ILC.MIMQ_SUCCESSFUL_CONNECTION:
|
|
1497
1499
|
raise ILOperationException((rep.getArg2() if rep is not None else "")
|
|
1498
1500
|
or "MIMQE_INVALID_MSG_FORMAT (connection)")
|
|
@@ -1534,9 +1536,10 @@ class ILTopicProducer:
|
|
|
1534
1536
|
self._connected = True
|
|
1535
1537
|
self._reconnect_attempts = 0
|
|
1536
1538
|
|
|
1537
|
-
def _request(self, conn: TCPConnector, code: int, *args: str):
|
|
1539
|
+
def _request(self, conn: TCPConnector, code: int, *args: str, ext: bytes = None):
|
|
1538
1540
|
with _io_lock_of(conn): # 0.7.3: 부트스트랩 전용 연결이지만 요청-응답 짝 규칙은 같게
|
|
1539
|
-
conn.send(ILMsgUtil.
|
|
1541
|
+
conn.send(ILMsgUtil.create_request_msg_with_ext(code, ext, *args)
|
|
1542
|
+
if ext is not None else ILMsgUtil.create_request_msg(code, *args))
|
|
1540
1543
|
res = conn.recv(self.config.get_request_timeout_ms())
|
|
1541
1544
|
if res.getType() == ILC.MIMQ_REPORT_MESSAGE:
|
|
1542
1545
|
return res.getReportMsg()
|
|
@@ -200,6 +200,17 @@ class _AutoAccessor:
|
|
|
200
200
|
field = name[2].lower() + name[3:]
|
|
201
201
|
if hasattr(self, field):
|
|
202
202
|
return lambda: bool(getattr(self, field))
|
|
203
|
+
# 0.18.0: 개명 안내를 **게터 호출에도** 붙인다. 전에는 대입 경로에만 있어서
|
|
204
|
+
# `p.getClusterType()` 이 맨 AttributeError 로 떨어졌다 - 정작 시험과 예제가
|
|
205
|
+
# 부딪히는 것은 게터 쪽이다.
|
|
206
|
+
for _pfx, _cut in (("get", 3), ("set", 3), ("is", 2)):
|
|
207
|
+
if name.startswith(_pfx) and len(name) > _cut:
|
|
208
|
+
moved = type(self)._RENAMED.get(name[_cut].lower() + name[_cut + 1:])
|
|
209
|
+
if moved is not None:
|
|
210
|
+
raise AttributeError(
|
|
211
|
+
f"{self.__class__.__name__} has no attribute {name}"
|
|
212
|
+
f" - {moved[1]} 에서 {moved[0]} 로 바뀌었다"
|
|
213
|
+
)
|
|
203
214
|
raise AttributeError(f"{self.__class__.__name__} has no attribute {name}")
|
|
204
215
|
|
|
205
216
|
_SPEC: dict = {}
|
|
@@ -3267,8 +3278,7 @@ class ILQmgrProperty(_AutoAccessor):
|
|
|
3267
3278
|
스펙: 기본 10485760 · 범위 1~1073741824000 · 단위 byte · 변경 가능/재기동 불필요.
|
|
3268
3279
|
subExpiryMinutes (int): 구독 만료(분). 기본 10080(7일).
|
|
3269
3280
|
스펙: 기본 10080 · 범위 0~2147483647 (0=비활성) · 단위 분 · 변경 가능/재기동 불필요.
|
|
3270
|
-
memberExpiryMinutes (int): 컨슈머 그룹 멤버 유휴 만료(분). 기본 5
|
|
3271
|
-
(Kafka ``max.poll.interval.ms`` 기본값에 대응).
|
|
3281
|
+
memberExpiryMinutes (int): 컨슈머 그룹 멤버 유휴 만료(분). 기본 5.
|
|
3272
3282
|
구독 옵션 ``expiryMs`` 가 이 값을 덮는다.
|
|
3273
3283
|
스펙: 기본 5 · 범위 1~9999 · 단위 분 · 변경 가능/재기동 불필요.
|
|
3274
3284
|
deadSessionKeepDuration (int): 끊긴 세션 정보 보관(초). 기본 600.
|
|
@@ -5292,11 +5302,11 @@ class ILSpokeProperty(_AutoAccessor):
|
|
|
5292
5302
|
#: 왼쪽 정렬 십진수로 썼고 ``MIMQ_RUNNING`` 이 **2** 라, 판 표시를 ``"2"`` 로 두면
|
|
5293
5303
|
#: 옛 블롭이 **"판 2 와 정확히 일치" 로 읽힌다**(거절도 아니고 "낮은 판" 도 아니다).
|
|
5294
5304
|
#: 글자로 시작하면 옛 블롭이 만들 수 없는 값이 되어 두 방향이 모두 막힌다.
|
|
5295
|
-
CLUSTER_LAYOUT_MARK = "
|
|
5305
|
+
CLUSTER_LAYOUT_MARK = "V%d" % ILC.MIMQ_CLUSTER_BLOB_VERSION
|
|
5296
5306
|
|
|
5297
5307
|
#: :data:`CLUSTER_LAYOUT_MARK` 의 숫자 부분. 비교는 이쪽으로 한다 - 문자열 비교는
|
|
5298
5308
|
#: ``"V10" < "V2"`` 로 갈린다.
|
|
5299
|
-
_CLUSTER_LAYOUT_NUMBER =
|
|
5309
|
+
_CLUSTER_LAYOUT_NUMBER = ILC.MIMQ_CLUSTER_BLOB_VERSION
|
|
5300
5310
|
|
|
5301
5311
|
#: :class:`ILClusterNode` 와이어 레이아웃 ``(속성 이름, 폭)``. **오프셋은 순서에서 계산한다** -
|
|
5302
5312
|
#: 폭이 조정돼도 이 표 한 줄만 고치면 파싱·직렬화·보존이 같이 따라간다.
|
|
@@ -5380,6 +5390,13 @@ class ILClusterNode(_AutoAccessor):
|
|
|
5380
5390
|
ctrlPort (int): 그 노드의 **컨트롤러 포트**. 문법에서 주소 뒤 ``/9000`` 자리다.
|
|
5381
5391
|
스펙: 범위 1025~65535 · 변경 불가.
|
|
5382
5392
|
coordinator (bool | None): 이 노드가 **컨트롤러 멤버**인가(문법의 ``COORDS``).
|
|
5393
|
+
엔진 rev 3463 이상이면 보낸 값이 **정의에 보존된다**(되읽으면 온다).
|
|
5394
|
+
☠ 다만 **동작에 쓰이는 것은 컨트롤러 정족수가 켜진 뒤**다 - 그전에는
|
|
5395
|
+
저장만 되고 아무 일도 일어나지 않는다.
|
|
5396
|
+
☠ 문법의 ``COORDS(1)`` 은 *"1번이 컨트롤러고 **나머지는 아니다**"* 라는
|
|
5397
|
+
완결된 진술이다. 블롭으로 같은 말을 하려면 나머지 노드를 **명시적으로
|
|
5398
|
+
``False``** 로 둬야 한다 - 빈칸으로 두면 *"모른다"* 가 되어 뜻이 다르다.
|
|
5399
|
+
컨트롤러 노드에는 **``ctrl_port`` 가 반드시** 있어야 한다.
|
|
5383
5400
|
★ **``None`` 은 "모름"** 이고 ``False``("아니다")와 **다르다**. 서버가 안
|
|
5384
5401
|
채웠거나 이 판이 모르는 값일 때 ``None`` 이다. 참/거짓으로 판정하지 말고
|
|
5385
5402
|
``is None`` 으로 먼저 가른다.
|
|
@@ -5660,7 +5677,11 @@ _CLUSTER_FIXED_FIELDS = (
|
|
|
5660
5677
|
("replicas", 5), ("minSync", 5),
|
|
5661
5678
|
("secretFile", 256),
|
|
5662
5679
|
("controllerLeader", 6), ("defTerm", 10), ("defVersion", 10),
|
|
5663
|
-
("signature", 20), ("statusReason", 96),
|
|
5680
|
+
("signature", 20), ("statusReason", 96),
|
|
5681
|
+
# 엔진 r3473 이 예약 앞 12바이트에 이름을 줬다. **판 번호는 안 올랐다**(V2 그대로) -
|
|
5682
|
+
# 이 클라는 모르는 자리를 원본째 되보내므로 이름이 붙기 전에도 아무 문제가 없었다.
|
|
5683
|
+
# ☠ 둘 다 **관측 전용**이다: 엔진이 나갈 때만 채우고 들어올 때는 지운다.
|
|
5684
|
+
("actingCoordinator", 6), ("localCtrlPort", 6), (None, 173),
|
|
5664
5685
|
)
|
|
5665
5686
|
|
|
5666
5687
|
_CLUSTER_OFF, _CLUSTER_LEN = _field_offsets(_CLUSTER_FIXED_FIELDS)
|
|
@@ -5765,6 +5786,11 @@ class ILClusterProperty(_AutoAccessor):
|
|
|
5765
5786
|
defVersion (int | None): **읽기 전용.** 이 정의의 **판 번호**.
|
|
5766
5787
|
★ ``defTerm`` 과 **쌍**이다. **0 은 정상값**이고 없음은 오직 ``None`` 이다.
|
|
5767
5788
|
signature (str): **읽기 전용.** 엔진이 정의에 붙이는 표식.
|
|
5789
|
+
actingCoordinator (int | None): **읽기 전용.** 승격을 집행하는 조정자의
|
|
5790
|
+
노드 번호. 모르면 ``None`` - **0 은 노드 번호가 아니다.**
|
|
5791
|
+
localCtrlPort (int | None): **읽기 전용.** 이 응답을 준 **서비스가 실제로
|
|
5792
|
+
듣고 있는** ilcc 포트. 정의에 적힌 값이 아니라 **관측값**이다.
|
|
5793
|
+
★ 둘 다 엔진이 **나갈 때만** 채운다 - 실어 보내도 무시된다.
|
|
5768
5794
|
nodes (list[ILClusterNode]): 클러스터를 이루는 노드 전부.
|
|
5769
5795
|
|
|
5770
5796
|
Note:
|
|
@@ -5806,11 +5832,15 @@ class ILClusterProperty(_AutoAccessor):
|
|
|
5806
5832
|
"defTerm": "엔진이 채우는 값이다",
|
|
5807
5833
|
"defVersion": "엔진이 채우는 값이다",
|
|
5808
5834
|
"signature": "엔진이 채우는 값이다",
|
|
5835
|
+
"actingCoordinator": "관측값이다 - 엔진이 나갈 때만 채운다",
|
|
5836
|
+
"localCtrlPort": "관측값이다 - 답한 서비스가 실제로 듣는 포트다",
|
|
5809
5837
|
}
|
|
5810
5838
|
|
|
5811
5839
|
_RENAMED = {
|
|
5812
5840
|
"clusterType": ("노드마다의 역할(ILClusterNode.is_broker / coordinator)", "0.17.0"),
|
|
5813
5841
|
"ilccPort": ("노드마다의 ILClusterNode.ctrlPort", "0.17.0"),
|
|
5842
|
+
"judge": ("노드마다의 ILClusterNode.is_coordinator", "0.17.0"),
|
|
5843
|
+
"coordinator": ("노드마다의 ILClusterNode.is_coordinator", "0.17.0"),
|
|
5814
5844
|
"authorityHolder": ("controllerLeader (노드 번호다)", "0.17.0"),
|
|
5815
5845
|
}
|
|
5816
5846
|
|
|
@@ -5826,15 +5856,15 @@ class ILClusterProperty(_AutoAccessor):
|
|
|
5826
5856
|
ba (bytes | bytearray | None): 서버가 보낸 바이트(키워드로도 줄 수 있다).
|
|
5827
5857
|
주면 나머지 인자는 무시된다.
|
|
5828
5858
|
|
|
5859
|
+
Raises:
|
|
5860
|
+
ILDeserializeException: 바이트 길이가 규격보다 짧거나, **판 표시가 없거나
|
|
5861
|
+
(레거시) 이 클라보다 높을 때.**
|
|
5862
|
+
|
|
5829
5863
|
Note:
|
|
5830
5864
|
★ **둘째 자리부터는 키워드로만 받는다.** 예전 둘째 자리는 ``ilcc_port`` 였다.
|
|
5831
5865
|
그대로 위치 인자를 받으면 ``ILClusterProperty("C1", 27091)`` 이 **예외 없이**
|
|
5832
5866
|
``is_auto_start = 27091`` 로 들어가 조용히 다른 뜻이 된다 - **자리 재사용은 제거보다
|
|
5833
5867
|
나쁘다.** 키워드 전용으로 막아 ``TypeError`` 로 터지게 한다.
|
|
5834
|
-
|
|
5835
|
-
Raises:
|
|
5836
|
-
ILDeserializeException: 바이트 길이가 규격보다 짧거나, **판 표시가 없거나
|
|
5837
|
-
(레거시) 이 클라보다 높을 때.**
|
|
5838
5868
|
"""
|
|
5839
5869
|
if isinstance(name, (bytes, bytearray)):
|
|
5840
5870
|
ba, name = name, ""
|
|
@@ -5855,6 +5885,8 @@ class ILClusterProperty(_AutoAccessor):
|
|
|
5855
5885
|
self.defTerm = None
|
|
5856
5886
|
self.defVersion = None
|
|
5857
5887
|
self.signature = ""
|
|
5888
|
+
self.actingCoordinator = None
|
|
5889
|
+
self.localCtrlPort = None
|
|
5858
5890
|
#: (내부) 서버가 준 고정부 원본. **읽기만 하는 자리와 읽지도 쓰지도 않는 구간을
|
|
5859
5891
|
#: 되돌려 보내기 위해** 들고 있다(:meth:`get_serialized` 참조).
|
|
5860
5892
|
self._rawBytes = b""
|
|
@@ -5905,6 +5937,10 @@ class ILClusterProperty(_AutoAccessor):
|
|
|
5905
5937
|
self.defTerm = ba_pick_int_opt(ba, o["defTerm"][0], o["defTerm"][1])
|
|
5906
5938
|
self.defVersion = ba_pick_int_opt(ba, o["defVersion"][0], o["defVersion"][1])
|
|
5907
5939
|
self.signature = ba_pick_string(ba, o["signature"][0], o["signature"][1])
|
|
5940
|
+
self.actingCoordinator = ba_pick_int_opt(ba, o["actingCoordinator"][0],
|
|
5941
|
+
o["actingCoordinator"][1])
|
|
5942
|
+
self.localCtrlPort = ba_pick_int_opt(ba, o["localCtrlPort"][0],
|
|
5943
|
+
o["localCtrlPort"][1])
|
|
5908
5944
|
_sr_off, _sr_len = o["statusReason"]
|
|
5909
5945
|
self.statusReason = bytes(ba[_sr_off:_sr_off + _sr_len]).split(b"\x00")[0].decode(
|
|
5910
5946
|
"utf-8", "replace")
|
|
@@ -5924,6 +5960,11 @@ class ILClusterProperty(_AutoAccessor):
|
|
|
5924
5960
|
Returns:
|
|
5925
5961
|
list[ILClusterNode]: ``coordinator`` 가 **True 인 노드만**. ``None``(모름)은
|
|
5926
5962
|
넣지 않는다 - 모르는 것을 정족수에 세면 정족수가 틀린다.
|
|
5963
|
+
|
|
5964
|
+
Note:
|
|
5965
|
+
☠ **빈 목록은 두 뜻이다** - *"컨트롤러가 없다"* 와 *"아직 모른다"*. 목록
|
|
5966
|
+
하나로는 삼상태를 못 싣는다. 가르려면 노드별
|
|
5967
|
+
:meth:`ILClusterNode.is_coordinator` 를 ``is None`` 으로 본다.
|
|
5927
5968
|
"""
|
|
5928
5969
|
return [n for n in self.nodes if n.coordinator is True]
|
|
5929
5970
|
|
|
@@ -5943,6 +5984,53 @@ class ILClusterProperty(_AutoAccessor):
|
|
|
5943
5984
|
|
|
5944
5985
|
getBrokerNodes = get_broker_nodes
|
|
5945
5986
|
|
|
5987
|
+
def _validate_addresses(self) -> None:
|
|
5988
|
+
"""노드 주소가 서로 겹치는지 **모든 짝**을 본다.
|
|
5989
|
+
|
|
5990
|
+
Raises:
|
|
5991
|
+
ILOperationException: 브로커 둘이 같은 ``(host, port)`` 를 들거나,
|
|
5992
|
+
노드 둘이 같은 ``(host, ctrlPort)`` 를 들 때
|
|
5993
|
+
(``MIMQE_INVALID_ARGUMENT``).
|
|
5994
|
+
|
|
5995
|
+
Note:
|
|
5996
|
+
★ **ctrl 포트 검사는 역할을 안 본다.** ctrl 포트는 *"컨트롤러의 투표
|
|
5997
|
+
포트"* 가 아니라 **그 서비스의 ilcc 포트**다 - 컨트롤러가 아닌 서비스도
|
|
5998
|
+
ilcc 를 돌린다(브로커에 붙어 하트비트와 승격을 한다). 컨트롤러끼리만
|
|
5999
|
+
보면 **역할 경계에 사각이 생긴다**(브로커 노드와 컨트롤러 전용 노드가
|
|
6000
|
+
같은 포트를 들어도 안 걸린다).
|
|
6001
|
+
|
|
6002
|
+
Note:
|
|
6003
|
+
☠ **한 호스트에 컨트롤러 전용 노드가 둘인 것은 여기서 막지 않는다.**
|
|
6004
|
+
주소가 다르면 정의는 정당하고(한 호스트에 서비스 둘이 각각 컨트롤러를
|
|
6005
|
+
들 수 있다), 엔진이 *"둘 중 내가 누구인지 못 가린다"* 는 것뿐이다. 그
|
|
6006
|
+
판정은 **요청을 받는 서비스가 누구인가**에 달렸는데 클라는 그것을
|
|
6007
|
+
모른다 - 걸면 **정당한 정의를 거절**하게 된다.
|
|
6008
|
+
|
|
6009
|
+
같은 이유로 **컨트롤러 수 {1, 3, 5} 도 여기서 안 본다.** 그것은 엔진
|
|
6010
|
+
정책이라 넓어질 수 있고, 그날 이 클라가 이유 없이 거절하는 쪽이 된다.
|
|
6011
|
+
⇒ 클라가 걸어도 되는 것은 **정의 자체로 판정되는 모순**뿐이다.
|
|
6012
|
+
"""
|
|
6013
|
+
seen: dict = {}
|
|
6014
|
+
for n in self.nodes: # 브로커끼리 데이터 주소
|
|
6015
|
+
if not n.is_broker():
|
|
6016
|
+
continue
|
|
6017
|
+
key = (n.host, n.port)
|
|
6018
|
+
if key in seen:
|
|
6019
|
+
raise ILOperationException(
|
|
6020
|
+
"MIMQE_INVALID_ARGUMENT (nodes %d and %d share qmgr port %d)"
|
|
6021
|
+
% (seen[key], n.nodeId, n.port))
|
|
6022
|
+
seen[key] = n.nodeId
|
|
6023
|
+
seen = {}
|
|
6024
|
+
for n in self.nodes: # ★ 역할 무관 - ctrl 포트가 있으면 본다
|
|
6025
|
+
if not n.ctrlPort:
|
|
6026
|
+
continue
|
|
6027
|
+
key = (n.host, n.ctrlPort)
|
|
6028
|
+
if key in seen:
|
|
6029
|
+
raise ILOperationException(
|
|
6030
|
+
"MIMQE_INVALID_ARGUMENT (nodes %d and %d share ctrl port %d)"
|
|
6031
|
+
% (seen[key], n.nodeId, n.ctrlPort))
|
|
6032
|
+
seen[key] = n.nodeId
|
|
6033
|
+
|
|
5946
6034
|
def get_node(self, node_id: int):
|
|
5947
6035
|
"""번호로 노드를 찾는다.
|
|
5948
6036
|
|
|
@@ -199,7 +199,7 @@ class ILQmgr:
|
|
|
199
199
|
그 외에는 사용법을 안내한다.
|
|
200
200
|
"""
|
|
201
201
|
if len(args) != 1:
|
|
202
|
-
print("available
|
|
202
|
+
print("available arguments.")
|
|
203
203
|
print(" --version : displays the library version.")
|
|
204
204
|
ILC.print_version(args[0] if args else "")
|
|
205
205
|
|
|
@@ -461,9 +461,11 @@ class ILQmgr:
|
|
|
461
461
|
conn_mode = ILC.MIMQ_SESSION_TRANSACTED
|
|
462
462
|
if auto_commit:
|
|
463
463
|
conn_mode = ILC.MIMQ_AUTO_ACKNOWLEDGE
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
)
|
|
464
|
+
# 0.18.0: 능력 선언. ☠ arg1(conn_mode)은 자동커밋 플래그라 건드리지 않는다.
|
|
465
|
+
_caps = ILC.client_caps_extension()
|
|
466
|
+
_cargs = ((ILC.MIMQ_NEW_CONNECTION,) + ((_caps,) if _caps else ())
|
|
467
|
+
+ (str(conn_mode), client_name, "USR"))
|
|
468
|
+
conn_res_msg = self.service.request(*_cargs)
|
|
467
469
|
if conn_res_msg is None:
|
|
468
470
|
raise ILOperationException("MIMQE_INTERNAL_ERROR")
|
|
469
471
|
if conn_res_msg.getCode() != ILC.MIMQ_SUCCESSFUL_CONNECTION:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|