Skip to content

Commit 67f8b2a

Browse files
authored
[releases/1.2] service: Fix tag deserialization for large messages (#554)
service: Fix tag deserialization for large messages (#552) * tests: Add test cases for big messages (100 fields) * service: Fix tag deserialization for large messages Tags are i32 varints, but we were only deserializing the first byte. Simplify some related details: - Decoding a varint returns the updated position, so we don't need to use encoder._TagSize() - We can directly construct a memory view once instead of constructing a BytesIO for each loop iteration. * tests: Use pytest.approx instead of choosing exactly comparable floats
1 parent 405f063 commit 67f8b2a

7 files changed

Lines changed: 534 additions & 24 deletions

File tree

ni_measurementlink_service/_internal/parameter/serializer.py

Lines changed: 7 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
from typing import Any, Dict, Sequence, cast
66

77
from google.protobuf.descriptor import FieldDescriptor
8-
from google.protobuf.internal import encoder
8+
from google.protobuf.internal.decoder import ( # type: ignore[attr-defined]
9+
_DecodeSignedVarint32,
10+
)
911
from google.protobuf.message import Message
1012

1113
from ni_measurementlink_service._internal.parameter import serialization_strategy
@@ -110,25 +112,6 @@ def serialize_default_values(parameter_metadata_dict: Dict[int, ParameterMetadat
110112
return serialize_parameters(parameter_metadata_dict, default_value_parameter_array)
111113

112114

113-
def _get_field_index(parameter_bytes: bytes, tag_position: int) -> int:
114-
"""Get the Filed Index based on the tag's position.
115-
116-
The tag Position should be the index of the TagValue in the ByteArray for valid field index.
117-
118-
Args
119-
----
120-
parameter_bytes (bytes): Serialized bytes
121-
122-
tag_position (int): Tag position
123-
124-
Returns
125-
-------
126-
int: Filed index of the Tag Position
127-
128-
"""
129-
return parameter_bytes[tag_position] >> _GRPC_WIRE_TYPE_BIT_WIDTH
130-
131-
132115
def _get_overlapping_parameters(
133116
parameter_metadata_dict: Dict[int, ParameterMetadata], parameter_bytes: bytes
134117
) -> Dict[int, Any]:
@@ -152,8 +135,10 @@ def _get_overlapping_parameters(
152135
# inner_decoder update the overlapping_parameters
153136
overlapping_parameters_by_id: Dict[int, Any] = {}
154137
position = 0
138+
parameter_bytes_memory_view = memoryview(parameter_bytes)
155139
while position < len(parameter_bytes):
156-
field_index = _get_field_index(parameter_bytes, position)
140+
(tag, position) = _DecodeSignedVarint32(parameter_bytes_memory_view, position)
141+
field_index = tag >> _GRPC_WIRE_TYPE_BIT_WIDTH
157142
if field_index not in parameter_metadata_dict:
158143
raise Exception(
159144
f"Error occurred while reading the parameter - given protobuf index '{field_index}' is invalid."
@@ -163,11 +148,9 @@ def _get_overlapping_parameters(
163148
field_metadata.type, field_metadata.repeated, field_metadata.message_type
164149
)
165150
inner_decoder = decoder(field_index, cast(FieldDescriptor, field_index))
166-
parameter_bytes_io = BytesIO(parameter_bytes)
167-
parameter_bytes_memory_view = parameter_bytes_io.getbuffer()
168151
position = inner_decoder(
169152
parameter_bytes_memory_view,
170-
position + encoder._TagSize(field_index), # type: ignore[attr-defined]
153+
position,
171154
len(parameter_bytes),
172155
cast(Message, None), # unused - See serialization_strategy._vector_decoder._new_default
173156
cast(Dict[FieldDescriptor, Any], overlapping_parameters_by_id),

tests/assets/bigmessage.proto

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
syntax = "proto3";
2+
package ni.measurementlink.measurement.tests.v1;
3+
4+
message BigMessage {
5+
double field1 = 1;
6+
double field2 = 2;
7+
double field3 = 3;
8+
double field4 = 4;
9+
double field5 = 5;
10+
double field6 = 6;
11+
double field7 = 7;
12+
double field8 = 8;
13+
double field9 = 9;
14+
double field10 = 10;
15+
double field11 = 11;
16+
double field12 = 12;
17+
double field13 = 13;
18+
double field14 = 14;
19+
double field15 = 15;
20+
double field16 = 16;
21+
double field17 = 17;
22+
double field18 = 18;
23+
double field19 = 19;
24+
double field20 = 20;
25+
double field21 = 21;
26+
double field22 = 22;
27+
double field23 = 23;
28+
double field24 = 24;
29+
double field25 = 25;
30+
double field26 = 26;
31+
double field27 = 27;
32+
double field28 = 28;
33+
double field29 = 29;
34+
double field30 = 30;
35+
double field31 = 31;
36+
double field32 = 32;
37+
double field33 = 33;
38+
double field34 = 34;
39+
double field35 = 35;
40+
double field36 = 36;
41+
double field37 = 37;
42+
double field38 = 38;
43+
double field39 = 39;
44+
double field40 = 40;
45+
double field41 = 41;
46+
double field42 = 42;
47+
double field43 = 43;
48+
double field44 = 44;
49+
double field45 = 45;
50+
double field46 = 46;
51+
double field47 = 47;
52+
double field48 = 48;
53+
double field49 = 49;
54+
double field50 = 50;
55+
double field51 = 51;
56+
double field52 = 52;
57+
double field53 = 53;
58+
double field54 = 54;
59+
double field55 = 55;
60+
double field56 = 56;
61+
double field57 = 57;
62+
double field58 = 58;
63+
double field59 = 59;
64+
double field60 = 60;
65+
double field61 = 61;
66+
double field62 = 62;
67+
double field63 = 63;
68+
double field64 = 64;
69+
double field65 = 65;
70+
double field66 = 66;
71+
double field67 = 67;
72+
double field68 = 68;
73+
double field69 = 69;
74+
double field70 = 70;
75+
double field71 = 71;
76+
double field72 = 72;
77+
double field73 = 73;
78+
double field74 = 74;
79+
double field75 = 75;
80+
double field76 = 76;
81+
double field77 = 77;
82+
double field78 = 78;
83+
double field79 = 79;
84+
double field80 = 80;
85+
double field81 = 81;
86+
double field82 = 82;
87+
double field83 = 83;
88+
double field84 = 84;
89+
double field85 = 85;
90+
double field86 = 86;
91+
double field87 = 87;
92+
double field88 = 88;
93+
double field89 = 89;
94+
double field90 = 90;
95+
double field91 = 91;
96+
double field92 = 92;
97+
double field93 = 93;
98+
double field94 = 94;
99+
double field95 = 95;
100+
double field96 = 96;
101+
double field97 = 97;
102+
double field98 = 98;
103+
double field99 = 99;
104+
double field100 = 100;
105+
}

tests/assets/bigmessage_pb2.py

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)