diff --git a/doc/internals/how-to-add-new-backend.rst b/doc/internals/how-to-add-new-backend.rst index 4352dd3df5b..9a4b7c47323 100644 --- a/doc/internals/how-to-add-new-backend.rst +++ b/doc/internals/how-to-add-new-backend.rst @@ -421,6 +421,9 @@ That implies that all the reference to open files should be dropped. For opening files, we therefore suggest to use the helper class provided by Xarray :py:class:`~xarray.backends.CachingFileManager`. +Note that any ``BackendArray`` subclass will also be protected such that any attempt +to write to this array only writes to a copy of whatever might still be stored on disk. + .. _RST indexing: Indexing examples diff --git a/xarray/backends/api.py b/xarray/backends/api.py index 670a0ec6d68..81f39682357 100644 --- a/xarray/backends/api.py +++ b/xarray/backends/api.py @@ -236,9 +236,16 @@ def _protect_dataset_variables_inplace(dataset, cache): for name, variable in dataset.variables.items(): if name not in dataset._indexes: # no need to protect IndexVariable objects - data = indexing.CopyOnWriteArray(variable._data) + + if isinstance(variable._data, backends.BackendArray): + # only need to protect arrays that were lazy-loaded from disk + data = indexing.CopyOnWriteArray(variable._data) + else: + data = variable._data + if cache: data = indexing.MemoryCachedArray(data) + variable.data = data diff --git a/xarray/core/indexing.py b/xarray/core/indexing.py index 6e6ce01a41f..a1958c0f637 100644 --- a/xarray/core/indexing.py +++ b/xarray/core/indexing.py @@ -652,6 +652,13 @@ def _wrap_numpy_scalars(array): class CopyOnWriteArray(ExplicitlyIndexedNDArrayMixin): + """ + Ensures that an attempt to write to this array only writes to a copy + of whatever might still be stored on disk. + + Used to wrap any array that inherits from BackendArray. + """ + __slots__ = ("array", "_copied") def __init__(self, array):