Rasterio: Add flush method to writer

Created on 19 Feb 2018  路  7Comments  路  Source: mapbox/rasterio

Calling close() flushes buffered data to storage, but not being able to flush when we want to flush is a missing feature or bug 馃毥馃槼

Current workaround:

# Copy GeoTIFF block-by-block.
import rasterio


source_path = 'original.tif'
copy_path = '/tmp/copy.tif'

# Create but do not fill the copy.
with rasterio.open(source_path) as src:
    with rasterio.open(copy_path, 'w', **src.profile) as dst:
        pass

# Copy data over, flushing each block.
with rasterio.open(source_path) as src, rasterio.open(copy_path, 'r+') as dst:
    for ij, window in dst.block_windows():
        data = src.read(window=window)
        with rasterio.open(dst.name, 'r+') as writer:
            writer.write(data, window=window)

In the future:

import rasterio


source_path = 'original.tif'
copy_path = '/tmp/copy.tif'

with rasterio.open(source_path) as src:
    with rasterio.open(copy_path, 'w', **src.profile) as writer:
        for ij, window in dst.block_windows():
            data = src.read(window=window)
            writer.write(data, window=window)
            writer.flush()
bug enhancement

All 7 comments

Like Python's open function, would it be possible to add an optional buffer kwarg that would allow an explicit configurable buffer size in addition to manual flush?

@perrygeo hmm, not sure, I don't know if we'll really know how many bytes GDAL has buffered.

Looks like the buffer size can be controlled by the GDAL_CACHEMAX config option.

Setting it to 100k (the lowest allowable value it appears) causes very frequent disk writes:
image

Setting to 1M defers the IO until we're part way through
image

Setting to 5M (greater than the size of the RGB.byte.tif test image) means IO only occurs when we close the dataset.
image

(see the gist for code)

The good news is that GDAL_CACHEMAX has sensible defaults; 5% of available memory should be a safe bet for most use cases to avoid unexpected memory errors. But it does mean that the IO behavior is not deterministic. Depending on the user's machine or their GDAL version, the IO could either happen within the block window loop and/or on close.

It looks like @perrygeo determined it is not practical, but I'm _very_ 馃憥 on hiding GDAL_CACHEMAX behind a buffer option similar to open(buffer=..). It is an environment level option (#1270) that affects all GDAL I/O, including Rasterio's use of in-memory rasters to translate Numpy arrays to GDAL datasets. Additionally, GDAL_CACHEMAX is only:

consulted the first time the cache size is requested overriding the initial default (40MB up to GDAL 2.0, 5% of the usable physical RAM starting with GDAL 2.1)

Altering the value requires going through GDALGetCacheMax() and GDALSetCacheMax(), and their 64 bit counterparts.

I have occasionally found use for the flush methods in the OSGeo bindings, but there are some driver-level considerations. GDAL caches at both the GDALRasterBand and GDALDataset level. Calling either object's FlushCache() method flushes known data, but a given driver may also sync some, all, or no data in GDALClose(). A driver may also override the flush methods and defer all I/O until GDALClose(). It seems like Rasterio should flush all bands and then the dataset. I see no reason for this to limit an implementation in Rasterio, but it seems like something that should be documented and communicated to the user.

@geowurster good point. Instead of touching the block cache size, the thing for a writer to do is track the number of pixels written and flush when the buffering limit has been reached.

@sgillies are you suggesting src.write() would call src.flush()?

Was this page helpful?
0 / 5 - 0 ratings

Related issues

valpesendorfer picture valpesendorfer  路  3Comments

sgillies picture sgillies  路  4Comments

astrojuanlu picture astrojuanlu  路  4Comments

gfairchild picture gfairchild  路  5Comments

mangecoeur picture mangecoeur  路  3Comments