{"record":{"id":"5e3fbcb9baec6c6b","repo":"apache/cassandra","slug":"unable-to-determine-filesystem-block-size-for-dire","errorCode":null,"errorMessage":"Unable to determine filesystem block size for Direct IO. Block size: %d","messagePattern":"Unable to determine filesystem block size for Direct IO\\. Block size: (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/java/org/apache/cassandra/io/compress/DirectCompressedSequentialWriter.java","lineNumber":111,"sourceCode":"    private int directBufferBytes = 0;\n\n    public DirectCompressedSequentialWriter(File file,\n                                            File offsetsFile,\n                                            @Nullable File digestFile,\n                                            SequentialWriterOption option,\n                                            CompressionParams parameters,\n                                            MetadataCollector sstableMetadataCollector,\n                                            @Nullable CompressionDictionaryManager compressionDictionaryManager)\n    {\n        super(file, offsetsFile, digestFile, option, parameters, sstableMetadataCollector, compressionDictionaryManager, ExtendedOpenOption.DIRECT);\n\n        // super() opened the O_DIRECT FileChannel and allocated parent buffers; if anything below throws\n        // the caller never gets a reference to clean them up, so abort the txn proxy ourselves.\n        try\n        {\n            this.blockSize = FileUtils.getBlockSize(file.parent());\n            if (blockSize <= 0)\n                throw new IllegalStateException(\"Unable to determine filesystem block size for Direct IO. \" +\n                                                \"Block size: \" + blockSize);\n\n            if (!BitUtil.isPowerOfTwo(blockSize))\n                throw new IllegalStateException(\"Filesystem block size must be a power of two for Direct IO. \" +\n                                                \"Block size: \" + blockSize);\n\n            int configuredSize = DatabaseDescriptor.getDirectWriteBufferSize().toBytes();\n            int maxChunkWrite = parameters.getSstableCompressor().initialCompressedBufferLength(parameters.chunkLength());\n            int minRequiredSize = maxChunkWrite + CRC_LENGTH + blockSize;\n            if (configuredSize < minRequiredSize && undersizedBufferWarned.compareAndSet(false, true))\n                logger.warn(\"direct_write_buffer_size ({} bytes) is below the minimum required for SSTable {} \" +\n                            \"(worst-case chunk {} + CRC 4 + blockSize {} = {} bytes); using the minimum. \" +\n                            \"Increase direct_write_buffer_size in cassandra.yaml to silence this warning.\",\n                            configuredSize, file, maxChunkWrite, blockSize, minRequiredSize);\n            int bufferSize = BitUtil.align(Math.max(configuredSize, minRequiredSize), blockSize);\n\n            this.writeBuffer = BufferUtil.allocateDirectAligned(bufferSize, blockSize);\n            this.directBufferBytes = bufferSize;","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/apache/cassandra/blob/88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1/src/java/org/apache/cassandra/io/compress/DirectCompressedSequentialWriter.java#L93-L129","documentation":"DirectCompressedSequentialWriter opens an O_DIRECT channel and must know the filesystem's logical block size to do aligned direct I/O. During construction it calls FileUtils.getBlockSize() on the file's parent directory; if the OS returns a non-positive value, the writer aborts with this IllegalStateException. The constructor deliberately throws inside its try block because the caller never receives the writer reference needed to clean up the already-opened channel and buffers, so the txn proxy is aborted in the catch path.","triggerScenarios":"Creating a Direct-IO compressed SSTable writer (DirectCompressedSequentialWriter public constructor) on a filesystem whose st_blksize (f_bsize) cannot be determined or is reported as <= 0 by FileUtils.getBlockSize(file.parent()).","commonSituations":"Running on exotic/unsupported filesystems (e.g. tmpfs configurations, FUSE mounts, some network filesystems) that report a zero or nonsensical block size; enabling the direct-io option in an environment where statvfs reports unusable values.","solutions":["Move the data directory to a filesystem that reports a valid, positive logical block size (ext4, xfs, etc.).","Check with `stat -f` or `stat -c %o` on the data directory what block size the kernel reports; if it is 0, the filesystem does not support Direct IO properly.","Disable the direct-io write path (do not enable Direct IO SSTable writing) if the storage layer cannot support it."],"exampleFix":"// before: node with direct-io enabled on a filesystem reporting blksize 0\nthrow new IllegalStateException(\"Unable to determine filesystem block size for Direct IO. Block size: \" + blockSize);\n// after (operator action): relocate data dir to a direct-io capable fs\n// cassandra.yaml / table option: direct_io = false  (or mount ext4/xfs)","handlingStrategy":"validation","validationCode":"long blockSize = FileUtils.getBlockSize(Paths.get(dataDir).toFile());\nif (blockSize <= 0) throw new IllegalStateException(\"Direct IO unsupported on \" + dataDir + \": block size \" + blockSize);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Check `stat -c %o <dataDir>` returns a positive power-of-two value before enabling direct-io.","Run direct IO only on proven filesystems (ext4, xfs on local block devices).","Smoke-test Direct IO SSTable writes in staging on the same storage stack as production."],"tags":["direct-io","filesystem","block-size","startup"],"backgroundTag":"unsupported-platform","analyzedSha":"88fd0f6a0eaed8943f05ac9e8f947882b8ddc8f1","analyzedAt":"2026-09-10T07:29:22.284Z","contentChangedAt":"2026-09-10T07:29:22.284Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}