-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
MDEV-35599: Replace (u
)llstr()
with %llu
/d
#3724
base: main
Are you sure you want to change the base?
Conversation
> `llstr()` is a workaround for printing longlongs > from the times when `%llu` was not supported Nearly all of (`u`)`llstr()` calls were preparations for calls to the `printf` extended family; but both the C/C++ `printf` family and our `my_vsnprintf()` & descendants already support `long long`s via the `ll` size specifier. Inlining `llstr()` saves an additional function call each *everywhere*, which reduces cognitive load and potentially improves performance too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great! these *llstr() annoyed me for quite a while. thanks!
35 files changed, 656 insertions(+), 1030 deletions(-)
And -400 lines, no bad.
See comments inline.
@@ -821,8 +820,7 @@ static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, | |||
if (is_stmt_end && !result) | |||
{ | |||
if (print_event_info->print_row_count) | |||
fprintf(result_file, "# Number of rows: %s\n", | |||
llstr(print_event_info->row_events, ll_buff)); | |||
fprintf(result_file, "# Number of rows: %lld\n", print_event_info->row_events); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
row_events
is ulonglong, that is unsigned. Were you getting a compiler error here?
you wrote it's a non-goal, so I will no longer comment on signed/unsigned mismatch, but would the code compile without you fixing it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it’s impractical to track typedefs manually when we can automatically catch them by turning on -Wformat-signedness
, so I explicitly excluded this step.
From what I can tell, neither -Wformat
nor -Wall
include -Wformat-signedness
, so issues like this continue not spawning compile warnings.
I mentioned -Wformat-signedness
as a comment of MDEV-26896.
We can prioritize it here or we can push for MDEV-26896 to ship with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔 Turning on -Wconversion
(MDEV-26896) will complain about cases like these before this replacement.
🧐 It will also complain about char *ullstr(longlong value,char *buff)
because it delegates a ulonglong
arg to longlong10_to_str(value,buff,10);
which is sign-agnostic.
@@ -335,21 +332,19 @@ int chk_size(HA_CHECK *param, register MI_INFO *info) | |||
{ | |||
error=1; | |||
mi_check_print_error(param, | |||
"Size of indexfile is: %-8s Should be: %s", | |||
llstr(size,buff), llstr(skr,buff2)); | |||
"Size of indexfile is: %-8lld Should be: %lld", size, skr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
%-8lld
-> %lld
?
same below and in Aria
llstr(info->s->base.max_key_file_length-1,buff)); | ||
mi_check_print_warning(param, | ||
"Keyfile is almost full, %10lld of %10lld used", | ||
info->state->key_file_length, info->s->base.max_key_file_length-1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll stop commenting on the width in %lld
. I think it make sense to specify the width in
- status output printfs, that print many rows and we want numbers to be aligned
- a warning/error that can be reported many times (e.g. some link is broken) and we want all numbers there to be aligned
if it's a warning/error that is reported only once per file like "file almost full", something in the header is wrong, etc — it doesn't need to align its numbers as there's nothing to align them with
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also did not question the purpose of minimum-length specifiers inherited from the original code.
I’ll think about it.
"Can't find key for index: %2d", | ||
llstr(start_recpos,llbuff),key+1); | ||
start_recpos, key+1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is one of the errors, I suppose, that can be reported many times for different records. So it kind of makes sense to align the offset here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven’t checked CI and the feedback’s already in.
Thank you, boss!
@@ -821,8 +820,7 @@ static bool print_row_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev, | |||
if (is_stmt_end && !result) | |||
{ | |||
if (print_event_info->print_row_count) | |||
fprintf(result_file, "# Number of rows: %s\n", | |||
llstr(print_event_info->row_events, ll_buff)); | |||
fprintf(result_file, "# Number of rows: %lld\n", print_event_info->row_events); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it’s impractical to track typedefs manually when we can automatically catch them by turning on -Wformat-signedness
, so I explicitly excluded this step.
From what I can tell, neither -Wformat
nor -Wall
include -Wformat-signedness
, so issues like this continue not spawning compile warnings.
I mentioned -Wformat-signedness
as a comment of MDEV-26896.
We can prioritize it here or we can push for MDEV-26896 to ship with it.
llstr(info->s->base.max_key_file_length-1,buff)); | ||
mi_check_print_warning(param, | ||
"Keyfile is almost full, %10lld of %10lld used", | ||
info->state->key_file_length, info->s->base.max_key_file_length-1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also did not question the purpose of minimum-length specifiers inherited from the original code.
I’ll think about it.
@@ -1538,8 +1537,7 @@ static void test_prepare() | |||
fprintf(stdout, "\n\t tiny : %d (%lu)", tiny_data, length[0]); | |||
fprintf(stdout, "\n\t short : %d (%lu)", small_data, length[3]); | |||
fprintf(stdout, "\n\t int : %d (%lu)", int_data, length[2]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The size specifier for char
is hh
.
But since varargs smaller than int
get auto-promoted to int
, I won’t judge it here (or press for h
support in my_vsnprintf
).
This “long
” type applied on an int
data itches me, though –
They probably meant Maria-SQL INT
, which is better defined with int32_t
(and format with "%"PRId32
) to strictly match INT4
.
Reviewed-by: Sergei Golubchik <[email protected]>
This one doesn't know the buffer size! So that's how I missed it in the previous commit.
`timeout` is a `double`, so use `double` operations
if (my_b_printf(file, "SET @@session.sql_mode=%llu%s\n", | ||
sql_mode, print_event_info->delimiter)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my_b_printf
does not support and ignores %llu
, causing segfaults here and likely erroneous outputs in other places.
my_b_printf
is another one of our printf
alternative that formats to my_b_write
.
It only supports format specifiers %s
, %c
, %d
/%u
and %ld
/%lu
(yes, they’re specifiers in its lexicon) and ignores others.
Notably, my_b_printf
also supports %b
and the `
flag for %s
similar to my_snprintf
; but that’s switching to %sB
and %sQ
, whereas my_b_printf
is a separate implementation independent of that.
When I migrated my_snprintf
users, I recognized that my_b_printf
isn’t part of the family and skipped over it.
That meant my_b_printf
would remain incompatible with -Wformat
and be “out of date” with the modified my_snprintf
.
Except my_b_printf
is causing trouble right now.
@vuvova, what shall we do about it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion — rewrite my_b_vprintf
copying the logic from my_vfprintf
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
and they will be consistent until the next time we update the my_snprintf
family.
🧐 I’m not sure about that. my_vfprintf
works by resizing its allocation until the result fits1, whereas my_b_write
writes to a limited buffer that only flushes when full.
Either case, I should mark this PR as on hold.
Footnotes
-
… which is not efficient; unfortunately, unlike C/C++
snprintf
,my_snprintf
doesn’t tell the number of bytes it would’ve written if the output buffer’s sufficient. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I mean, my_b_vprintf
could write to a buffer, resizing it like my_vfprintf
does. Agree, it's not the best approach, but fixing it would be a separate task. At the end my_b_vprintf
would use my_b_write
to write the buffer to IO_CACHE
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have another idea.
We can modify the implementation of my_vsnprintf
to instead build around a writer callback, say bool (*writer)(void *reference, char *string, int string_length)
that returns whether the loop should halt.
When respective buffers fill up, regular my_vsnprintf
’s callback would return a halt request, while both my_vfprintf
’s and my_b_vprintf
’s would flush and carry on.
Of course, because my_vsnprintf
is divided to many subfunction components, this approach is intrusive and very complex.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure. That's why it wasn't implemented yet. In particular, it wasn't implemented, when we needed my_vfprintf
.
A compromise approach — simpler than yours, more complex than what I suggested earlier — would be to make my_vsnprint_ex
to return, as you wrote, number of bytes it would have written if the buffer were big enough. In this approach my_vsnprint
can still return what it does now, it's a public API function and if we want to be conservative, we won't change it. But the internal my_vsnprint_ex
can be changed to return whatever we want, and my_vfprintf
can call it directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👌 Let’s put then on the backburner for now; I have higher-priority assignments.
Description
What problem is the patch trying to solve?
Nearly all of (
u
)llstr()
calls were preparations for calls to theprintf
extended family; but both the C/C++printf
family and ourmy_snprintf()
& descendants already supportlong long
s through thell
size specifier.Inlining
llstr()
saves an additional function call each everywhere, whichlong long
is too large for the buffer given tollstr()
Original Question: Which
llstr(value, buff)
can we replace withsprintf(buff, "%lld", value)
?Answer: all but about a dozen of a few hundred of them!
I approached this task by deleting (
u
)llstr()
functions entirely, which leaves these dozen-ish ones to calllonglong10_to_str(value,buff,-10);
directly.As this
longlong10_to_str()
will be incompatible with MDEV-26896’s-Wconversion
, that task (whenever it begins) will most likely revive (u
)llstr()
to splitlonglong10_to_str()
as.Real motivation
I wanted to modernize our ancient code.2
In addition, I visited lots of files across components during project-wide cleanups like this and #3360, which helps me familiarize with the repository (and its state of maintenance) as a new recruit of the Corp.
Non-goals
llstr()
calls (replaced with"%lld"
) should rather useullstr()
(which would be"%llu"
)ullstr
calls currently.-Wformat-signedness
on will warn3 these mistakes."%"PRId64
,"%"PRIu64
and%zu
are likely more accurate.longlong
-Wformat
4 complaints, such assql/sql_test.cc
llstr
to convertint
s andlong
s to strings… ¯\_(ツ)_/¯Release Notes
TODO: Ask QA engineers for their impressions on this housekeeping
How can this PR be tested?
llstr()
usage that it’s eitherprintf
by replacing%s
with%lld
snprintf(…, "%lld", …)
longlong10_to_str(…, …, -10)
-Wformat
Checks onmy_vsnprintf
and Users #3360 with this commit4Basing the PR against the correct MariaDB version
main
branch.PR quality check
Footnotes
I don’t think we have one right now… 😶🌫️ ↩
See also: https://justforfunnoreally.dev ↩
We also have
-Werror
active. ↩ ↩2-Wformat
currently only supports the C/C++printf
family; [MDEV-21978 part 2] Enable and Fix GCC-Wformat
Checks onmy_vsnprintf
and Users #3360 of MDEV-21978 will add support formy_vsnprintf
and descendants. ↩ ↩2