{"record":{"id":"19269c796009d032","repo":"microsoft/garnet","slug":"sketch-size-should-be-power-of-2","errorCode":null,"errorMessage":"Sketch size should be power of 2!","messagePattern":"Sketch size should be power of 2!","errorType":"validation","errorClass":"GarnetException","httpStatus":null,"severity":"error","filePath":"libs/cluster/Server/Migration/Sketch.cs","lineNumber":25,"sourceCode":"using Garnet.common;\nusing Garnet.server;\nusing Tsavorite.core;\n\nnamespace Garnet.cluster\n{\n    internal class Sketch\n    {\n        readonly byte[] bitmap;\n        readonly int size;\n        public readonly ArgSliceVector argSliceVector;\n\n        public List<(PinnedSpanByte, bool)> Keys { private set; get; }\n        public SketchStatus Status { private set; get; }\n\n        public Sketch(int keyCount = 1 << 20)\n        {\n            if (!(keyCount > 0 && (keyCount & (keyCount - 1)) == 0))\n                throw new GarnetException($\"{nameof(Sketch)} size should be power of 2!\");\n            size = keyCount;\n            bitmap = GC.AllocateArray<byte>(keyCount >> 3, pinned: true);\n            Status = SketchStatus.INITIALIZING;\n            Keys = [];\n            argSliceVector = new();\n        }\n\n        #region sketchMethods\n\n        public bool TryHashAndStore(ReadOnlySpan<byte> key)\n        {\n            if (!argSliceVector.TryAddItem(key))\n                return false;\n\n            var slot = (int)HashUtils.MurmurHash2x64A(key) & (size - 1);\n            var byteOffset = slot >> 3;\n            var bitOffset = slot & 7;\n            bitmap[byteOffset] = (byte)(bitmap[byteOffset] | (1UL << bitOffset));","sourceCodeStart":7,"sourceCodeEnd":43,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/cluster/Server/Migration/Sketch.cs#L7-L43","documentation":"Thrown by the Sketch constructor when keyCount is not a positive power of two. The bitmap is allocated as keyCount>>3 bytes and addressed with a bitmask, so the power-of-two requirement is structural, not cosmetic. The default is 1<<20.","triggerScenarios":"Constructing new Sketch(n) where n <= 0 or n is not a power of two (e.g. 1_000_000, 7, 0).","commonSituations":"Passing a user-supplied or computed key-count estimate directly without rounding up to the next power of two; passing 0 for a no-op migration.","solutions":["Round the requested size up to the next power of two before constructing the Sketch (e.g. BitOperations.RoundUpToPowerOf2).","Clamp the input to a sensible minimum (e.g. 1<<10) before rounding.","Validate at the call site and surface a clear error to the operator rather than the raw exception."],"exampleFix":"// before\nvar sketch = new Sketch(estimatedKeyCount);\n// after\nusing System.Numerics;\nvar size = (int)BitOperations.RoundUpToPowerOf2((uint)Math.Max(1, estimatedKeyCount));\nvar sketch = new Sketch(size);","handlingStrategy":"validation","validationCode":"// Normalize to a valid power-of-two size before construction\nusing System.Numerics;\nint size = (int)BitOperations.RoundUpToPowerOf2((uint)Math.Max(1, requestedKeyCount));\nif (size <= 0) throw new ArgumentOutOfRangeException(nameof(requestedKeyCount));\nvar sketch = new Sketch(size);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always round estimated key counts up to the next power of two before constructing a Sketch.","Clamp to a minimum size to avoid degenerate 0/1 cases.","Reject zero or negative counts at the API boundary."],"tags":["cluster","migration","sketch","validation","garnet"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}