Fix GEOHASH last character: always output '0' for Redis compatibility#1635
Fix GEOHASH last character: always output '0' for Redis compatibility#1635
Conversation
Co-authored-by: badrishc <18355833+badrishc@users.noreply.github.com>
|
Request your review on this PR, @sspeaks and @PaulusParssinen |
There was a problem hiding this comment.
Pull request overview
Updates Garnet’s GEOHASH output to match Redis behavior by forcing the 11th (final) geohash character to '0', since Garnet stores only 52 bits of precision (insufficient for the full 55 bits implied by 11 base32 characters).
Changes:
- Adjust
GeoHash.GetGeoHashCodeto force the last base32 character index to0(so the last character is always'0'). - Update geohash expectations in unit/integration tests to reflect the new Redis-compatible output.
- Change the pinned .NET SDK version in
global.jsonfrom10.0.103to10.0.102.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| libs/server/Objects/SortedSetGeo/GeoHash.cs | Forces the last geohash character to '0' for Redis compatibility under 52-bit precision. |
| test/Garnet.test/GeoHashTests.cs | Updates expected geohash strings and clarifies the '0' last-character convention. |
| test/Garnet.test/RespSortedSetGeoTests.cs | Updates expected GEOHASH output in RESP sorted set geo tests (e.g., Palermo). |
| global.json | Updates the repo’s pinned .NET SDK patch version. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| "sdk": { | ||
| "version": "10.0.103", | ||
| "version": "10.0.102", | ||
| "rollForward": "latestMajor", |
| // For compatibility with Redis, the last character is always '0' since the | ||
| // remaining bits are not stored with sufficient precision to determine it. | ||
| var idx = i < chars.Length - 1 | ||
| ? (int)(hash >> (BitsOfPrecision - 5)) & 0x1F |
There was a problem hiding this comment.
Consider instead something along the lines of
var base32Chars = "0123456789bcdefghjkmnpqrstuvwxyz"u8;
// We have just 52 bits, but the API outputs an 11-character geohash (55 bits).
// For compatibility with Redis, the last character is always '0'.
chars[^1] = '0';
for (var i = 0; i < chars.Length - 1; i++)
{
// Shift and mask the five most significant bits for index to the base-32 table.
chars[i] = (char)base32Chars[(int)(hash >> (BitsOfPrecision - 5)) & 0x1F];
// Shift the encoded bits out.
hash <<= 5;
}
PaulusParssinen
left a comment
There was a problem hiding this comment.
Added comment with alternative approach without branches in the inner loop, either will do the job.
All other GEO* functionality will still use the available 52-bit precision that is persisted in the sorted set.
Garnet's
GEOHASHproduces a wrong 11th character because geohash strings require 55 bits (11 × 5) but geo scores are stored as 52-bit integers — the final 3 bits don't exist. Redis sets the last character to'0'by convention; Garnet was computing it from undefined bit positions.Changes
GeoHash.cs—GetGeoHashCode: force index0on the last iteration instead of shifting undefined bits:GeoHashTests.cs: update all expected geohash strings — last character is now always'0'(e.g.wm3vxz6vywh→wm3vxz6vyw0,zzzzzzzzzzs→zzzzzzzzzz0); update comment to clarify the'0'convention.RespSortedSetGeoTests.cs: update expected Palermo geohashsqc8b49rnys→sqc8b49rny0.Original prompt
📱 Kick off Copilot coding agent tasks wherever you are with GitHub Mobile, available on iOS and Android.