{"record":{"id":"0a485216013d01e0","repo":"alibaba/canal","slug":"buffersize-must-be-a-power-of-2-0a4852","errorCode":null,"errorMessage":"bufferSize must be a power of 2","messagePattern":"bufferSize must be a power of 2","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"store/src/main/java/com/alibaba/otter/canal/store/memory/MemoryEventStoreWithBuffer.java","lineNumber":86,"sourceCode":"    private Condition         notFull       = lock.newCondition();\n    private Condition         notEmpty      = lock.newCondition();\n\n    private BatchMode         batchMode     = BatchMode.ITEMSIZE;                        // 默认为内存大小模式\n    private boolean           ddlIsolation  = false;\n    private boolean           raw           = true;                                      // 针对entry是否开启raw模式\n\n    public MemoryEventStoreWithBuffer(){\n\n    }\n\n    public MemoryEventStoreWithBuffer(BatchMode batchMode){\n        this.batchMode = batchMode;\n    }\n\n    public void start() throws CanalStoreException {\n        super.start();\n        if (Integer.bitCount(bufferSize) != 1) {\n            throw new IllegalArgumentException(\"bufferSize must be a power of 2\");\n        }\n\n        indexMask = bufferSize - 1;\n        entries = new Event[bufferSize];\n    }\n\n    public void stop() throws CanalStoreException {\n        super.stop();\n\n        cleanAll();\n    }\n\n    public void put(List<Event> data) throws InterruptedException, CanalStoreException {\n        if (data == null || data.isEmpty()) {\n            return;\n        }\n\n        final ReentrantLock lock = this.lock;","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/store/src/main/java/com/alibaba/otter/canal/store/memory/MemoryEventStoreWithBuffer.java#L68-L104","documentation":"Thrown in MemoryEventStoreWithBuffer.start() when Integer.bitCount(bufferSize) != 1, i.e. bufferSize is not exactly a power of two. The ring buffer relies on bitwise masking (indexMask = bufferSize - 1; index = sequence & indexMask), which only wraps correctly for power-of-two sizes, so a non-compliant size is rejected at startup before the buffer can corrupt indices.","triggerScenarios":"Configuring canal.instance.memory.buffer.size to a value that is not a power of two (e.g. 1000, 3000, 50000) and starting the instance. The start() guard computes bit count and aborts.","commonSituations":"Operator sets a 'round' buffer size like 1000 or 16380 expecting decimal sizing; copy-pasting a size from another system; misreading the property as byte count vs entry count.","solutions":["Set canal.instance.memory.buffer.size to the nearest power of two (e.g. 1024, 2048, 4096, 8192, 16384).","Validate the configured value at deploy time with Integer.bitCount(size) == 1.","Round up to the next power of two to preserve the intended capacity."],"exampleFix":"// before\ncanal.instance.memory.buffer.size = 1000\n// after\ncanal.instance.memory.buffer.size = 1024","handlingStrategy":"validation","validationCode":"int size = config.getBufferSize();\nif (Integer.bitCount(size) != 1 || size <= 0) {\n    throw new IllegalArgumentException(\n        \"bufferSize must be a power of 2, got \" + size + \"; nearest valid: \" + Integer.highestOneBit(size - 1) * 2);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Document the power-of-two constraint next to the buffer.size property in every instance template.","Add a startup config validator that fails fast with the nearest valid size.","Common safe values: 1024, 2048, 4096, 8192, 16384, 32768."],"tags":["store","configuration","ring-buffer","startup","validation"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}