Skip to content

Commit c95e3a3

Browse files
avargitster
authored andcommitted
send-email: move trivial config handling to Perl
Optimize the startup time of git-send-email by using an amended config_regexp() function to retrieve the list of config keys and values we're interested in. For boolean keys we can handle the [true|false] case ourselves, and the "--get" case didn't need any parsing. Let's leave "--path" and other "--bool" cases to "git config". I'm not bothering with the "undef" or "" case (true and false, respectively), let's just punt on those and others and have "git config --type=bool" handle it. The "grep { defined } @values" here covers a rather subtle case. For list values such as sendemail.to it is possible as with any other config key to provide a plain "-c sendemail.to", i.e. to set the key as a boolean true. In that case the Git::config() API will return an empty string, but this new parser will correctly return "undef". However, that means we can end up with "undef" in the middle of a list. E.g. for sendemail.smtpserveroption in conjuction with sendemail.smtpserver as a path this would have produce a warning. For most of the other keys we'd behave the same despite the subtle change in the value, e.g. sendemail.to would behave the same because Mail::Address->parse() happens to return an empty list if fed "undef". For the boolean values we were already prepared to handle these variables being initialized as undef anyway. This brings the runtime of "git send-email" from ~60-~70ms to a very steady ~40ms on my test box. We now run just one "git config" invocation on startup instead of 8, the exact number will differ based on the local sendemail.* config. I happen to have 8 of those set. This brings the runtime of t9001-send-email.sh from ~13s down to ~12s for me. The change there is less impressive as many of those tests set various config values, and we're also getting to the point of diminishing returns for optimizing "git send-email" itself. Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5a544a4 commit c95e3a3

File tree

1 file changed

+21
-8
lines changed

1 file changed

+21
-8
lines changed

git-send-email.perl

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,11 @@ sub read_config {
334334
my $target = $config_bool_settings{$setting};
335335
my $key = "$prefix.$setting";
336336
next unless exists $known_keys->{$key};
337-
my $v = Git::config_bool(@repo, $key);
337+
my $v = (@{$known_keys->{$key}} == 1 &&
338+
(defined $known_keys->{$key}->[0] &&
339+
$known_keys->{$key}->[0] =~ /^(?:true|false)$/s))
340+
? $known_keys->{$key}->[0] eq 'true'
341+
: Git::config_bool(@repo, $key);
338342
next unless defined $v;
339343
next if $configured->{$setting}++;
340344
$$target = $v;
@@ -363,13 +367,13 @@ sub read_config {
363367
my $key = "$prefix.$setting";
364368
next unless exists $known_keys->{$key};
365369
if (ref($target) eq "ARRAY") {
366-
my @values = Git::config(@repo, $key);
367-
next unless @values;
370+
my @values = @{$known_keys->{$key}};
371+
@values = grep { defined } @values;
368372
next if $configured->{$setting}++;
369373
@$target = @values;
370374
}
371375
else {
372-
my $v = Git::config(@repo, $key);
376+
my $v = $known_keys->{$key}->[0];
373377
next unless defined $v;
374378
next if $configured->{$setting}++;
375379
$$target = $v;
@@ -381,12 +385,19 @@ sub config_regexp {
381385
my ($regex) = @_;
382386
my @ret;
383387
eval {
384-
@ret = Git::command(
388+
my $ret = Git::command(
385389
'config',
386-
'--name-only',
390+
'--null',
387391
'--get-regexp',
388392
$regex,
389393
);
394+
@ret = map {
395+
# We must always return ($k, $v) here, since
396+
# empty config values will be just "key\0",
397+
# not "key\nvalue\0".
398+
my ($k, $v) = split /\n/, $_, 2;
399+
($k, $v);
400+
} split /\0/, $ret;
390401
1;
391402
} or do {
392403
# If we have no keys we're OK, otherwise re-throw
@@ -399,8 +410,10 @@ sub config_regexp {
399410
# parses 'bool' etc.) by only doing so for config keys that exist.
400411
my %known_config_keys;
401412
{
402-
my @known_config_keys = config_regexp("^sende?mail[.]");
403-
@known_config_keys{@known_config_keys} = ();
413+
my @kv = config_regexp("^sende?mail[.]");
414+
while (my ($k, $v) = splice @kv, 0, 2) {
415+
push @{$known_config_keys{$k}} => $v;
416+
}
404417
}
405418

406419
# sendemail.identity yields to --identity. We must parse this

0 commit comments

Comments
 (0)