{"record":{"id":"84884e17b59488a2","repo":"microsoft/garnet","slug":"nameof-logsettings-memorysize-must-be-at-least-84884e","errorCode":null,"errorMessage":"{nameof(logSettings.MemorySize)} must be at least twice the page size ({1L << rcs.PageSizeBits})","messagePattern":"(.+?) must be at least twice the page size \\((.+?)\\)","errorType":"validation","errorClass":"TsavoriteException","httpStatus":null,"severity":"error","filePath":"libs/storage/Tsavorite/cs/src/core/Allocator/AllocatorBase.cs","lineNumber":575,"sourceCode":"            if (logSettings.MemorySize != 0 && (logSettings.MemorySize < 1L << LogSettings.kMinMemorySizeBits || logSettings.MemorySize > 1L << LogSettings.kMaxMemorySizeBits))\n                throw new TsavoriteException($\"{nameof(logSettings.MemorySize)} must be between {1L << LogSettings.kMinMemorySizeBits} and {1L << LogSettings.kMaxMemorySizeBits}, or may be 0 for ReadOnly TsavoriteLog\");\n            if ((logSettings.MemorySize != 0) && (logSettings.MemorySize < (1L << logSettings.PageSizeBits) * LogSettings.kMinPageCount))\n                throw new TsavoriteException($\"{nameof(logSettings.MemorySize)} must be at least {LogSettings.kMinPageCount}x the page size ({1L << logSettings.PageSizeBits})\");\n            if (logSettings.MutableFraction < 0.0 || logSettings.MutableFraction > 1.0)\n                throw new TsavoriteException($\"{nameof(logSettings.MutableFraction)} must be >= 0.0 and <= 1.0\");\n            if (logSettings.ReadCacheSettings is not null)\n            {\n                var rcs = logSettings.ReadCacheSettings;\n                if (rcs.PageCount == 0 && rcs.MemorySize == 0)\n                    throw new TsavoriteException($\"{nameof(rcs.PageCount)} or {nameof(rcs.MemorySize)} must be specified\");\n                if (rcs.PageSizeBits < LogSettings.kMinPageSizeBits || rcs.PageSizeBits > LogSettings.kMaxPageSizeBits)\n                    throw new TsavoriteException($\"{nameof(rcs.PageSizeBits)} must be between {LogSettings.kMinPageSizeBits} and {LogSettings.kMaxPageSizeBits}\");\n                if (rcs.PageCount > MemoryUtils.ArrayMaxLength)\n                    throw new TsavoriteException($\"{nameof(rcs.PageCount)} must be less than or equal to the maximum array length ({MemoryUtils.ArrayMaxLength})\");\n                if (rcs.MemorySize != 0 && (rcs.MemorySize < 1L << LogSettings.kMinMemorySizeBits || rcs.MemorySize > 1L << LogSettings.kMaxMemorySizeBits))\n                    throw new TsavoriteException($\"{nameof(rcs.MemorySize)} must be between {1L << LogSettings.kMinMemorySizeBits} and {1L << LogSettings.kMaxMemorySizeBits}\");\n                if ((rcs.MemorySize != 0) && (rcs.MemorySize < (1L << rcs.PageSizeBits) * 2))\n                    throw new TsavoriteException($\"{nameof(logSettings.MemorySize)} must be at least twice the page size ({1L << rcs.PageSizeBits})\");\n                if (rcs.SecondChanceFraction < 0.0 || rcs.SecondChanceFraction > 1.0)\n                    throw new TsavoriteException($\"{rcs.SecondChanceFraction} must be >= 0.0 and <= 1.0\");\n            }\n\n            if (logSettings.MaxInlineKeySize < LogSettings.MinMaxInlineSize || logSettings.MaxInlineKeySize > LogSettings.MaxInlineKeySizeLimit)\n                throw new TsavoriteException($\"{nameof(logSettings.MaxInlineKeySize)} must be between {LogSettings.MinMaxInlineSize} and {LogSettings.MaxInlineKeySizeLimit}\");\n            if (logSettings.MaxInlineValueSize < LogSettings.MinMaxInlineSize || logSettings.MaxInlineValueSize > LogSettings.MaxInlineValueSizeLimit)\n                throw new TsavoriteException($\"{nameof(logSettings.MaxInlineValueSize)} must be between {LogSettings.MinMaxInlineSize} and {LogSettings.MaxInlineValueSizeLimit}\");\n\n            this.logger = logger;\n            if (logSettings.LogDevice == null)\n                throw new TsavoriteException(\"LogSettings.LogDevice needs to be specified (e.g., use Devices.CreateLogDevice, AzureStorageDevice, or NullDevice)\");\n\n            EvictCallback = evictCallback;\n\n            FlushCallback = flushCallback;\n            PreallocateLog = logSettings.PreallocateLog;\n            flushEvent.Initialize();","sourceCodeStart":557,"sourceCodeEnd":593,"githubUrl":"https://github.com/microsoft/garnet/blob/951b0fc6838721f89d102c2bbe1b914e8d39d700/libs/storage/Tsavorite/cs/src/core/Allocator/AllocatorBase.cs#L557-L593","documentation":"Constructor validation for the read cache: when rcs.MemorySize is non-zero it must be at least twice the read-cache page size (2 * (1 << rcs.PageSizeBits)), so the read-cache ring can hold >= 2 pages. Note the message text has a copy-paste bug: it reports 'logSettings.MemorySize' even though the guard actually checks rcs.MemorySize (the read-cache memory). Treat the message as referring to the read cache.","triggerScenarios":"Enabling a read cache with `ReadCacheSettings.PageSizeBits` large and `MemorySize` small, e.g. rcs.PageSizeBits=25 (32MiB) with rcs.MemorySize=16MiB: 16MiB < 2 * 32MiB.","commonSituations":"Mirroring a large main-log page size into the read cache without scaling rcs.MemorySize; tiny read-cache budget in tests.","solutions":["Raise rcs.MemorySize to at least 2 * (1 << rcs.PageSizeBits).","Or lower rcs.PageSizeBits so the budget covers >= 2 pages.","When the message mentions logSettings.MemorySize, verify rcs.MemorySize first (the message is misleading)."],"exampleFix":"// before (note: misleading message blames logSettings.MemorySize)\nrcs.PageSizeBits = 25;        // 32MiB\nrcs.MemorySize   = 1L << 24;  // 16MiB -> < 2 pages\n// after\nrcs.MemorySize   = 1L << 26;  // 64MiB -> 2 pages","handlingStrategy":"validation","validationCode":"// Read-cache memory must be >= 2 * read-cache page size.\n// NOTE: the library message incorrectly names logSettings.MemorySize; the real guard is on rcs.MemorySize.\nif (logSettings.ReadCacheSettings is { } rcs && rcs.MemorySize != 0)\n{\n    long minRcs = (1L << rcs.PageSizeBits) * 2;\n    if (rcs.MemorySize < minRcs) rcs.MemorySize = minRcs;\n}","typeGuard":null,"tryCatchPattern":"try { new TsavoriteKV<K,V>(logSettings, ...); }\ncatch (TsavoriteException ex) when (ex.Message.Contains(\"at least twice the page size\"))\n{ /* the culprit is rcs.MemorySize (message is misleading); raise it to >= 2*(1<<rcs.PageSizeBits) */ }","preventionTips":["When this message appears, check rcs.MemorySize first — the message wrongly blames logSettings.MemorySize.","Keep rcs.PageSizeBits <= log2(rcs.MemorySize / 2).","Add a regression test that asserts read-cache memory >= 2 pages."],"tags":["storage","configuration","log-settings","read-cache","memory","page-size","bug-in-message"],"backgroundTag":null,"analyzedSha":"951b0fc6838721f89d102c2bbe1b914e8d39d700","analyzedAt":"2026-08-13T19:01:32.939Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}