diff --git a/libs/server/Objects/SortedSetGeo/GeoHash.cs b/libs/server/Objects/SortedSetGeo/GeoHash.cs index 7fe7bc4a900..3b8eb412196 100644 --- a/libs/server/Objects/SortedSetGeo/GeoHash.cs +++ b/libs/server/Objects/SortedSetGeo/GeoHash.cs @@ -237,7 +237,11 @@ public static string GetGeoHashCode(long hash) { var base32Chars = "0123456789bcdefghjkmnpqrstuvwxyz"u8; - for (var i = 0; i < chars.Length; i++) + // 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]; diff --git a/test/Garnet.test/GeoHashTests.cs b/test/Garnet.test/GeoHashTests.cs index 1b93a84d1d4..e3198e21b16 100644 --- a/test/Garnet.test/GeoHashTests.cs +++ b/test/Garnet.test/GeoHashTests.cs @@ -42,15 +42,15 @@ public void CanEncodeAndDecodeCoordinates(double latitude, double longitude) } [Test] - [TestCase(30.5388942218, 104.0555758833, 4024744861876082, "wm3vxz6vywh")] - [TestCase(27.988056, 86.925278, 3636631039000829, "tuvz4p141z8")] + [TestCase(30.5388942218, 104.0555758833, 4024744861876082, "wm3vxz6vyw0")] + [TestCase(27.988056, 86.925278, 3636631039000829, "tuvz4p141z0")] [TestCase(37.502669, 15.087269, 3476216502357864, "sqdtr74hyu0")] - [TestCase(38.115556, 13.361389, 3476004292229755, "sqc8b49rnys")] - [TestCase(38.918250, -77.427944, 1787100258949719, "dqbvqhfenps")] + [TestCase(38.115556, 13.361389, 3476004292229755, "sqc8b49rny0")] + [TestCase(38.918250, -77.427944, 1787100258949719, "dqbvqhfenp0")] [TestCase(0.0, 0.0, 0xC000000000000, "s0000000000")] [TestCase(-90.0, -180.0, 0, "00000000000")] - [TestCase(90.0, 180.0, 0xFFFFFFFFFFFFF, "zzzzzzzzzzs")] - [TestCase(89.99999999999999, 179.99999999999997, 0xFFFFFFFFFFFFF, "zzzzzzzzzzs")] + [TestCase(90.0, 180.0, 0xFFFFFFFFFFFFF, "zzzzzzzzzz0")] + [TestCase(89.99999999999999, 179.99999999999997, 0xFFFFFFFFFFFFF, "zzzzzzzzzz0")] public void CanEncodeAndDecodeCoordinatesWithGeoHashCode( double latitude, double longitude, @@ -62,8 +62,9 @@ public void CanEncodeAndDecodeCoordinatesWithGeoHashCode( ClassicAssert.AreEqual(expectedHashInteger, hashInteger); - // Note: while we are comparing the entire textual representation of geohash (11 characters) - // we are comparing in 52-bit precision, not 55-bit that is expected from GeoHash standard. + // Note: while we are comparing the entire textual representation of geohash (11 characters), + // the data is stored in 52-bit precision (not 55-bit as required by the GeoHash standard). + // For compatibility with Redis, the last character is always '0'. ClassicAssert.AreEqual(expectedHash, hash); } } diff --git a/test/Garnet.test/RespSortedSetGeoTests.cs b/test/Garnet.test/RespSortedSetGeoTests.cs index ad8a5b4fa80..719e747fe74 100644 --- a/test/Garnet.test/RespSortedSetGeoTests.cs +++ b/test/Garnet.test/RespSortedSetGeoTests.cs @@ -221,7 +221,7 @@ public void CanUseGeoPos() var responseHash = db.GeoHash(new RedisKey("SecondKey"), ["Palermo"]); ClassicAssert.AreEqual(1, responseHash.Length); - ClassicAssert.AreEqual("sqc8b49rnys", responseHash[0]); + ClassicAssert.AreEqual("sqc8b49rny0", responseHash[0]); memresponse = db.Execute("MEMORY", "USAGE", "SecondKey"); actualValue = ResultType.Integer == memresponse.Resp2Type ? Int32.Parse(memresponse.ToString()) : -1; @@ -590,16 +590,16 @@ public void CanUseGeoHash(int bytesSent) var response = lightClientRequest.Execute("GEOADD Sicily 13.361389 38.115556 Palermo 15.087269 37.502669 Catania", "PING", expectedResponse.Length, bytesSent); ClassicAssert.AreEqual(expectedResponse, response); - expectedResponse = "*3\r\n$11\r\nsqc8b49rnys\r\n$11\r\nsqdtr74hyu0\r\n$-1\r\n+PONG\r\n"; + expectedResponse = "*3\r\n$11\r\nsqc8b49rny0\r\n$11\r\nsqdtr74hyu0\r\n$-1\r\n+PONG\r\n"; response = lightClientRequest.Execute("GEOHASH Sicily Palermo Catania Unknown", "PING", expectedResponse.Length, bytesSent); ClassicAssert.AreEqual(expectedResponse, response); - expectedResponse = "*3\r\n$11\r\nsqc8b49rnys\r\n$11\r\nsqdtr74hyu0\r\n$-1\r\n"; + expectedResponse = "*3\r\n$11\r\nsqc8b49rny0\r\n$11\r\nsqdtr74hyu0\r\n$-1\r\n"; response = lightClientRequest.Execute("GEOHASH Sicily Palermo Catania Unknown", expectedResponse.Length, bytesSent); ClassicAssert.AreEqual(expectedResponse, response); // Execute command in chunks - expectedResponse = "*1\r\n$11\r\nsqc8b49rnys\r\n"; + expectedResponse = "*1\r\n$11\r\nsqc8b49rny0\r\n"; response = lightClientRequest.Execute("GEOHASH Sicily Palermo", expectedResponse.Length, bytesSent); ClassicAssert.AreEqual(expectedResponse, response); }