|
19 | 19 |
|
20 | 20 | #include <fluent-bit/flb_log_event_encoder.h> |
21 | 21 | #include <fluent-bit/flb_log_event_encoder_primitives.h> |
| 22 | +#include <fluent-bit/flb_byteswap.h> |
22 | 23 | #include <stdarg.h> |
| 24 | +#include <string.h> |
| 25 | + |
| 26 | +/* |
| 27 | + * Encoder hot-path optimization notes (emit_record / commit_record / metadata): |
| 28 | + * |
| 29 | + * 1. emit_record: For FLUENT_BIT_V2 we use a direct-emit path that writes |
| 30 | + * the record string [ [timestamp, metadata], body ] directly into the |
| 31 | + * main buffer (no root buffer build/copy), matching the original format. |
| 32 | + * |
| 33 | + * 2. Possible future improvements: |
| 34 | + * - Batch metadata: add append_metadata_kv_batch() or allow multiple |
| 35 | + * key-value pairs in one call to cut va_list and call overhead. |
| 36 | + * - Inline / fast path: move begin_record/commit_record hot branches |
| 37 | + * into a header so the compiler can inline for the common case. |
| 38 | + * - Buffer growth: reserve space for the next record (e.g. typical |
| 39 | + * metadata + body size) to reduce reallocs in msgpack_sbuffer. |
| 40 | + * - dynamic_field_flush: when there is only one scope per field, avoid |
| 41 | + * the scope loop (single commit then set data/size). |
| 42 | + */ |
23 | 43 |
|
24 | 44 | void static inline flb_log_event_encoder_update_internal_state( |
25 | 45 | struct flb_log_event_encoder *context) |
@@ -144,71 +164,120 @@ int flb_log_event_encoder_emit_raw_record(struct flb_log_event_encoder *context, |
144 | 164 | return result; |
145 | 165 | } |
146 | 166 |
|
| 167 | +/* |
| 168 | + * Optimized emit_record: for FLUENT_BIT_V2 appends the record as raw |
| 169 | + * msgpack array bytes [ [timestamp, metadata], body ] to the main buffer |
| 170 | + * (no root buffer build/copy), matching the slow path format. |
| 171 | + */ |
147 | 172 | int flb_log_event_encoder_emit_record(struct flb_log_event_encoder *context) |
148 | 173 | { |
149 | | - int result; |
| 174 | + int result; |
| 175 | + char ts_buf[8]; |
| 176 | + char rec_header[5]; |
| 177 | + uint32_t sec; |
| 178 | + uint32_t nsec; |
150 | 179 |
|
151 | 180 | if (context == NULL) { |
152 | 181 | return FLB_EVENT_ENCODER_ERROR_INVALID_CONTEXT; |
153 | 182 | } |
154 | 183 |
|
155 | 184 | result = FLB_EVENT_ENCODER_SUCCESS; |
156 | 185 |
|
157 | | - /* This function needs to be improved and optimized to avoid excessive |
158 | | - * memory copying operations. |
159 | | - */ |
160 | | - |
161 | | - /* This conditional accounts for external raw record emission as |
162 | | - * performed by some filters using either |
163 | | - * flb_log_event_encoder_set_root_from_raw_msgpack |
164 | | - * or |
165 | | - * flb_log_event_encoder_set_root_from_msgpack_object |
166 | | - */ |
167 | 186 | if (context->root.size == 0) { |
168 | | - result = flb_log_event_encoder_root_begin_array(context); |
| 187 | + if (context->format == FLB_LOG_EVENT_FORMAT_FLUENT_BIT_V2 && |
| 188 | + context->metadata.data != NULL && context->body.data != NULL) { |
| 189 | + /* |
| 190 | + * Direct-emit: append raw array bytes [ [timestamp, metadata], body ] |
| 191 | + * (fixarray 2, fixarray 2, fixext 8 type 0, 8b ts, metadata, body). |
| 192 | + * Do not wrap in a msgpack string; match slow path which uses |
| 193 | + * msgpack_pack_str_body(root.data, root.size) with no str header. |
| 194 | + */ |
| 195 | + rec_header[0] = (char) 0x92; |
| 196 | + rec_header[1] = (char) 0x92; |
| 197 | + rec_header[2] = (char) 0xd7; |
| 198 | + rec_header[3] = (char) 0x00; |
| 199 | + |
| 200 | + result = msgpack_pack_str_body(&context->packer, |
| 201 | + rec_header, (size_t) 4); |
| 202 | + if (result == 0) { |
| 203 | + sec = FLB_UINT32_TO_NETWORK_BYTE_ORDER((uint32_t) context->timestamp.tm.tv_sec); |
| 204 | + nsec = FLB_UINT32_TO_NETWORK_BYTE_ORDER((uint32_t) context->timestamp.tm.tv_nsec); |
| 205 | + memcpy(&ts_buf[0], &sec, 4); |
| 206 | + memcpy(&ts_buf[4], &nsec, 4); |
| 207 | + result = msgpack_pack_str_body(&context->packer, ts_buf, 8); |
| 208 | + } |
| 209 | + if (result == 0) { |
| 210 | + result = msgpack_pack_str_body(&context->packer, |
| 211 | + context->metadata.data, |
| 212 | + context->metadata.size); |
| 213 | + } |
| 214 | + if (result == 0) { |
| 215 | + result = msgpack_pack_str_body(&context->packer, |
| 216 | + context->body.data, |
| 217 | + context->body.size); |
| 218 | + } |
| 219 | + if (result != 0) { |
| 220 | + result = FLB_EVENT_ENCODER_ERROR_SERIALIZATION_FAILURE; |
| 221 | + } |
| 222 | + else { |
| 223 | + result = FLB_EVENT_ENCODER_SUCCESS; |
| 224 | + } |
| 225 | + } |
| 226 | + else { |
| 227 | + result = flb_log_event_encoder_root_begin_array(context); |
| 228 | + |
| 229 | + if (context->format == FLB_LOG_EVENT_FORMAT_FLUENT_BIT_V2) { |
| 230 | + if (result == FLB_EVENT_ENCODER_SUCCESS) { |
| 231 | + result = flb_log_event_encoder_root_begin_array(context); |
| 232 | + } |
| 233 | + } |
169 | 234 |
|
170 | | - if (context->format == FLB_LOG_EVENT_FORMAT_FLUENT_BIT_V2) { |
171 | 235 | if (result == FLB_EVENT_ENCODER_SUCCESS) { |
172 | | - result = flb_log_event_encoder_root_begin_array(context); |
| 236 | + result = flb_log_event_encoder_append_root_timestamp( |
| 237 | + context, &context->timestamp); |
173 | 238 | } |
174 | | - } |
175 | 239 |
|
176 | | - if (result == FLB_EVENT_ENCODER_SUCCESS) { |
177 | | - result = flb_log_event_encoder_append_root_timestamp( |
178 | | - context, &context->timestamp); |
179 | | - } |
| 240 | + if (context->format == FLB_LOG_EVENT_FORMAT_FLUENT_BIT_V2) { |
| 241 | + if (result == FLB_EVENT_ENCODER_SUCCESS) { |
| 242 | + result = flb_log_event_encoder_append_root_raw_msgpack( |
| 243 | + context, |
| 244 | + context->metadata.data, |
| 245 | + context->metadata.size); |
| 246 | + } |
| 247 | + |
| 248 | + if (result == FLB_EVENT_ENCODER_SUCCESS) { |
| 249 | + result = flb_log_event_encoder_root_commit_array(context); |
| 250 | + } |
| 251 | + } |
180 | 252 |
|
181 | | - if (context->format == FLB_LOG_EVENT_FORMAT_FLUENT_BIT_V2) { |
182 | 253 | if (result == FLB_EVENT_ENCODER_SUCCESS) { |
183 | 254 | result = flb_log_event_encoder_append_root_raw_msgpack( |
184 | 255 | context, |
185 | | - context->metadata.data, |
186 | | - context->metadata.size); |
| 256 | + context->body.data, |
| 257 | + context->body.size); |
187 | 258 | } |
188 | 259 |
|
189 | | - /* We need to explicitly commit the current array (which |
190 | | - * holds the timestamp and metadata elements so we leave |
191 | | - * that scope and go back to the root scope where we can |
192 | | - * append the body element. |
193 | | - */ |
194 | 260 | if (result == FLB_EVENT_ENCODER_SUCCESS) { |
195 | | - result = flb_log_event_encoder_root_commit_array(context); |
| 261 | + result = flb_log_event_encoder_dynamic_field_flush(&context->root); |
196 | 262 | } |
197 | | - } |
198 | | - |
199 | | - if (result == FLB_EVENT_ENCODER_SUCCESS) { |
200 | | - result = flb_log_event_encoder_append_root_raw_msgpack( |
201 | | - context, |
202 | | - context->body.data, |
203 | | - context->body.size); |
204 | | - } |
205 | 263 |
|
206 | | - if (result == FLB_EVENT_ENCODER_SUCCESS) { |
207 | | - result = flb_log_event_encoder_dynamic_field_flush(&context->root); |
| 264 | + if (result == FLB_EVENT_ENCODER_SUCCESS && |
| 265 | + context->root.data != NULL && context->root.size > 0) { |
| 266 | + result = msgpack_pack_str_body(&context->packer, |
| 267 | + context->root.data, |
| 268 | + context->root.size); |
| 269 | + |
| 270 | + if (result != 0) { |
| 271 | + result = FLB_EVENT_ENCODER_ERROR_SERIALIZATION_FAILURE; |
| 272 | + } |
| 273 | + else { |
| 274 | + result = FLB_EVENT_ENCODER_SUCCESS; |
| 275 | + } |
| 276 | + } |
208 | 277 | } |
209 | 278 | } |
210 | | - |
211 | | - if (result == FLB_EVENT_ENCODER_SUCCESS) { |
| 279 | + else if (result == FLB_EVENT_ENCODER_SUCCESS && |
| 280 | + context->root.data != NULL && context->root.size > 0) { |
212 | 281 | result = msgpack_pack_str_body(&context->packer, |
213 | 282 | context->root.data, |
214 | 283 | context->root.size); |
|
0 commit comments