4
4
"encoding/binary"
5
5
"errors"
6
6
"fmt"
7
+ "github.com/godzie44/go-uring/uring"
7
8
"os"
8
9
9
10
pool "github.com/libp2p/go-buffer-pool"
@@ -21,14 +22,14 @@ type FileWriter struct {
21
22
open bool
22
23
closed bool
23
24
24
- file * os.File
25
- bufWriter WriteCloserFlusher
26
- currentOffset uint64
27
- compressionType int
28
- compressor compressor.CompressionI
29
- recordHeaderCache []byte
30
- bufferPool * pool.BufferPool
31
- directIOEnabled bool
25
+ file * os.File
26
+ bufWriter WriteCloserFlusher
27
+ currentOffset uint64
28
+ compressionType int
29
+ compressor compressor.CompressionI
30
+ recordHeaderCache []byte
31
+ bufferPool * pool.BufferPool
32
+ alignedBlockWrites bool
32
33
}
33
34
34
35
var DirectIOSyncWriteErr = errors .New ("currently not supporting directIO with sync writing" )
@@ -59,7 +60,7 @@ func (w *FileWriter) Open() error {
59
60
60
61
// we flush early to get a valid file with header written, this is important in crash scenarios
61
62
// when directIO is enabled however, we can't write misaligned blocks - thus this is not executed
62
- if ! w .directIOEnabled {
63
+ if ! w .alignedBlockWrites {
63
64
err = w .bufWriter .Flush ()
64
65
if err != nil {
65
66
return fmt .Errorf ("flushing header in file at '%s' failed with %w" , w .file .Name (), err )
@@ -160,9 +161,10 @@ func (w *FileWriter) Write(record []byte) (uint64, error) {
160
161
return prevOffset , nil
161
162
}
162
163
163
- // WriteSync appends a record of bytes and forces a disk sync, returns the current offset this item was written to
164
+ // WriteSync appends a record of bytes and forces a disk sync, returns the current offset this item was written to.
165
+ // When directIO is enabled however, we can't write misaligned blocks and immediately returns DirectIOSyncWriteErr
164
166
func (w * FileWriter ) WriteSync (record []byte ) (uint64 , error ) {
165
- if w .directIOEnabled {
167
+ if w .alignedBlockWrites {
166
168
return 0 , DirectIOSyncWriteErr
167
169
}
168
170
@@ -205,11 +207,14 @@ func (w *FileWriter) Size() uint64 {
205
207
// options
206
208
207
209
type FileWriterOptions struct {
208
- path string
209
- file * os.File
210
- compressionType int
211
- bufferSizeBytes int
212
- useDirectIO bool
210
+ path string
211
+ file * os.File
212
+ compressionType int
213
+ bufferSizeBytes int
214
+ enableDirectIO bool
215
+ enableIOUring bool
216
+ ioUringNumRingEntries uint32
217
+ ioUringOpts []uring.SetupOption
213
218
}
214
219
215
220
type FileWriterOption func (* FileWriterOptions )
@@ -246,21 +251,35 @@ func BufferSizeBytes(p int) FileWriterOption {
246
251
}
247
252
}
248
253
249
- // DirectIO is experimental: this flag enables DirectIO while writing, this currently might not work due to the misaligned allocations
254
+ // DirectIO is experimental: this flag enables DirectIO while writing. This has some limitation when writing headers and
255
+ // disables the ability to use WriteSync.
250
256
func DirectIO () FileWriterOption {
251
257
return func (args * FileWriterOptions ) {
252
- args .useDirectIO = true
258
+ args .enableDirectIO = true
259
+ }
260
+ }
261
+
262
+ // IOUring is experimental: this flag enables async writes using io_uring. This has some limitation around platform, it
263
+ // needs Linux and recent 5.x kernel to work. This currently also does not work together with DirectIO.
264
+ func IOUring (numRingEntries uint32 , opts ... uring.SetupOption ) FileWriterOption {
265
+ return func (args * FileWriterOptions ) {
266
+ args .enableIOUring = true
267
+ args .ioUringNumRingEntries = numRingEntries
268
+ args .ioUringOpts = opts
253
269
}
254
270
}
255
271
256
272
// NewFileWriter creates a new writer with the given options, either Path or File must be supplied, compression is optional.
257
273
func NewFileWriter (writerOptions ... FileWriterOption ) (WriterI , error ) {
258
274
opts := & FileWriterOptions {
259
- path : "" ,
260
- file : nil ,
261
- compressionType : CompressionTypeNone ,
262
- bufferSizeBytes : DefaultBufferSize ,
263
- useDirectIO : false ,
275
+ path : "" ,
276
+ file : nil ,
277
+ compressionType : CompressionTypeNone ,
278
+ bufferSizeBytes : DefaultBufferSize ,
279
+ enableDirectIO : false ,
280
+ enableIOUring : false ,
281
+ ioUringNumRingEntries : 4 ,
282
+ ioUringOpts : nil ,
264
283
}
265
284
266
285
for _ , writeOption := range writerOptions {
@@ -271,13 +290,19 @@ func NewFileWriter(writerOptions ...FileWriterOption) (WriterI, error) {
271
290
return nil , errors .New ("NewFileWriter: either os.File or string path must be supplied, never both" )
272
291
}
273
292
293
+ if opts .enableIOUring && opts .enableDirectIO {
294
+ return nil , errors .New ("NewFileWriter: either directIO or io_uring must be enabled, never both" )
295
+ }
296
+
274
297
if opts .path == "" {
275
298
opts .path = opts .file .Name ()
276
299
}
277
300
278
301
var factory ReaderWriterCloserFactory
279
- if opts .useDirectIO {
302
+ if opts .enableDirectIO {
280
303
factory = DirectIOFactory {}
304
+ } else if opts .enableIOUring {
305
+ factory = NewIOUringFactory (opts .ioUringNumRingEntries , opts .ioUringOpts ... )
281
306
} else {
282
307
factory = BufferedIOFactory {}
283
308
}
@@ -294,18 +319,18 @@ func NewFileWriter(writerOptions ...FileWriterOption) (WriterI, error) {
294
319
if err != nil {
295
320
return nil , fmt .Errorf ("failed to create new Writer at '%s' failed with %w" , opts .path , err )
296
321
}
297
- return newCompressedFileWriterWithFile (file , writer , opts .compressionType , opts .useDirectIO )
322
+ return newCompressedFileWriterWithFile (file , writer , opts .compressionType , opts .enableDirectIO )
298
323
}
299
324
300
325
// creates a new writer with the given os.File, with the desired compression
301
- func newCompressedFileWriterWithFile (file * os.File , bufWriter WriteCloserFlusher , compType int , directIOEnabled bool ) (WriterI , error ) {
326
+ func newCompressedFileWriterWithFile (file * os.File , bufWriter WriteCloserFlusher , compType int , alignedBlockWrites bool ) (WriterI , error ) {
302
327
return & FileWriter {
303
- file : file ,
304
- bufWriter : bufWriter ,
305
- directIOEnabled : directIOEnabled ,
306
- open : false ,
307
- closed : false ,
308
- compressionType : compType ,
309
- currentOffset : 0 ,
328
+ file : file ,
329
+ bufWriter : bufWriter ,
330
+ alignedBlockWrites : alignedBlockWrites ,
331
+ open : false ,
332
+ closed : false ,
333
+ compressionType : compType ,
334
+ currentOffset : 0 ,
310
335
}, nil
311
336
}
0 commit comments