strxfrm output stability

Paul Eggert eggert@cs.ucla.edu
Wed Sep 9 22:25:00 GMT 2015


On 09/09/2015 12:45 PM, Zack Weinberg wrote:
> On 09/09/2015 03:05 PM, Paul Eggert wrote:
>> When I tried a decade ago to use strxfrm in GNU sort to speed it up, I
>> ran into two problems.  First, glibc strxfrm generates lengthy output,
>> and since I wanted only the first 8 bytes or so I got relatively little
>> information out of the prefix and overall it was a performance loss on
>> my benchmarks.
> That's interesting, because as *I* understand it, that is exactly what
> PostgreSQL is doing

Again, I looked at the 9.4.4 code, but it is doing something fancier and 
I imagine 9.5 will too.  First, it's computing strxfrm for a range of 
keys, and if the strxfrm transformations of the minimum and maximum keys 
agree in the first B bytes, it discards the length-B prefix of all the 
strxfrm transformations.  Second, the code looks at the individual bytes 
of the strxfrm output, and if they're all (say) in the range 'A' through 
'Z' it compresses each of them to ~4.7bits (log base 2 of 26).  
PostgreSQL can do fun stuff like that because it uses floating-point 
comparators.

> they apparently got burnt a time or two by some C
> libraries reporting strings as strcoll-identical when they aren't
> byte-identical).

As I understand it POSIX allows this behavior, i.e., strcoll is allowed 
to return 0 even when its arguments are not byte-for-byte identical.  I 
observed this behavior in glibc with this program:

   #include <locale.h>
   #include <string.h>
   #include <stdio.h>

   int
   main (void)
   {
     if (! setlocale (LC_ALL, "en_US.UTF-8"))
       perror ("setlocale");
     return strcoll("\xc9\xa2", "\xc9\xac") == 0;
   }

On my Fedora host this silently exits with status 1.  Although this is 
arguably a bug, I don't see where it violates POSIX.

> It seems like there are two distinct use cases here: 1) grab a short, 
> fixed-length tag (effectively a collation-preserving hash); collisions 
> are OK, caller promises to fall back to strcoll() (PostgreSQL, 
> sort(1). 2) smuggle a locale-aware comparison into an API that only 
> allows you to provide a key, not a comparator (Python 3). Maybe it's 
> time to invent a new API? zw 

More generally for case (1) one may also want to discard a leading 
prefix as described above.



More information about the Libc-alpha mailing list