Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Getitems: support meta_array - #1131

Merged
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems
Apr 13, 2023
Merged

Getitems: support meta_array#1131
rabernat merged 33 commits into
zarr-developers:mainfrom
madsbk:getitems

Conversation

@madsbk

@madsbkmadsbk commented Sep 12, 2022

Copy link
Copy Markdown
Contributor

BaseStore now implements getitems(), which takes a meta_array argument. Besides simplifying the code, this enable stores to read directly to GPU memory: rapidsai/kvikio#131

TODO:

  • Add unit tests and/or doctests in docstrings
  • Add docstrings and API docs for any new/modified user-facing classes and functions
  • New/modified features documented in docs/tutorial.rst
  • Changes documented in docs/release.rst
  • GitHub Actions have all passed
  • Test coverage is 100% (Codecov passes)

@lgtm-com

lgtm-comBot commented Sep 12, 2022

Copy link
Copy Markdown

This pull request introduces 1 alert when merging 26b7d2d into b677db3 - view on LGTM.com

new alerts:

  • 1 for Signature mismatch in overriding method

@codecov

codecovBot commented Sep 12, 2022

Copy link
Copy Markdown

Codecov Report

Merging #1131 (a1d3520) into main (4b0705c) will not change coverage.
The diff coverage is 100.00%.

@@ Coverage Diff @@## main #1131 +/- ##
=========================================
Coverage 100.00% 100.00% =========================================
Files 36 37 +1 Lines 14799 14855 +56 =========================================
+ Hits 14799 14855 +56 
Impacted FilesCoverage Δ
zarr/_storage/store.py100.00% <100.00%> (ø)
zarr/context.py100.00% <100.00%> (ø)
zarr/core.py100.00% <100.00%> (ø)
zarr/storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage.py100.00% <100.00%> (ø)
zarr/tests/test_storage_v3.py100.00% <100.00%> (ø)
zarr/tests/test_util.py100.00% <100.00%> (ø)
zarr/tests/util.py100.00% <100.00%> (ø)
zarr/util.py100.00% <100.00%> (ø)

... and 2 files with indirect coverage changes

@madsbk
madsbk marked this pull request as ready for review September 13, 2022 11:16
@quasiben

Copy link
Copy Markdown

Is this the last PR needed by kvik for full Zarr support ?

@madsbk

madsbk commented Sep 21, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

@jakirkhamjakirkham left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Mads! This is very helpful 🙏

Asked one question above about API design. Curious to hear yours and others thoughts 🙂

reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Know fsspec-based storage layers are using a dict return value, but am wondering if we should be doing something different (like returning an iterable). Asking since this would make the read blocking vs. a bit more lazy. The latter can be useful when working with operations that take a bit longer (like reading from the cloud or parallelizing several reads)

cc @martindurant (who also may have thoughts)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The point of it being blocking, is that many keys may be being fetched concurrently. If you make it an iterator, you lose that, unless you have something that can wait on an async iterator, which in turn has first-completed working.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with both of you.
The API specifies a return type of Mapping[str, Any] thus it is possible to return a lazy mapping that only reads self[k] when accessed. But let's do that in a follow up PR?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, and will be interested in how that looks.

By the way, I mentioned elsewhere the possibility of passing key-specific metadata to the get function; that would happen in this same signature. I wonder if you have any use for an array where only some of it is destined for the GPU (perhaps because that data already exists there and doesn't need loading at all).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As noted above, think this discussion gets hairy enough it should be broken out into an issue (likely two) and discussed separately.

If we want to go the contexts route, we don't need a meta_array argument

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this also imply that getitem() should have a contexts parameter?

Good point, yes getitem() should also take a contexts parameter

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait a second, there is no getitem() and _chunk_getitem() anymore :)

@jakirkham

Copy link
Copy Markdown
Member

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

@madsbk

madsbk commented Sep 26, 2022

Copy link
Copy Markdown
ContributorAuthor

Is this the last PR needed by kvik for full Zarr support ?

Yes with this PR and rapidsai/kvikio#131, all building blocks should be in place to use Zarr backed by CuPy arrays!

Just to clarify, this is a quite useful optimization (and much appreciated!). Though is it a requirement (in that an error was hit somewhere)? Is there a bit more context about how this came up (particularly if an issue was encountered)?

It is required in the sense that a backend doesn’t know the memory destination of a read without this PR. In KvikIO’s backend, we must rely on key names to infer if the data goes to host or device memory. E.g. the following code check for keys that should go to host memory always:

ifos.path.basename(fn) in [
zarr.storage.array_meta_key,
zarr.storage.group_meta_key,
zarr.storage.attrs_key,
]:

This is a problem since a Store can define its own special keys with arbitrary names.

@jakirkham

Copy link
Copy Markdown
Member

Thanks for clarifying. Do we need setitems as well?

@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks for clarifying. Do we need setitems as well?

I don't think it is as important as the getitems since a backend can always probe the input data and determine if it is host or device memory.
However, setitems would make it possible to implement concurrent write, which could benefit backends such as KvikIO significantly.

Comment threadzarr/core.py Outdated
@jakirkham

Copy link
Copy Markdown
Member

@joshmoore do you have thoughts on this one? 🙂

@joshmoorejoshmoore left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor comments, @jakirkham. I do get the feeling that after the refactoring that enabled V3, we likely do need some storage-extension-specific documentation notes.

Comment threadzarr/_storage/store.py Outdated
Comment threadzarr/_storage/store.py Outdated
reads of multiple keys and/or to utilize the meta_array argument.
"""

return {k: self[k] for k in keys if k in self}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have an example of what they would look like, @martindurant?

Comment threadzarr/core.py
# store selected data in output
out[out_selection] = tmp

def _chunk_getitem(self, chunk_coords, chunk_selection, out, out_selection,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this so private that no one could have made use of it in a subclass?

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, AFAICT.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah that's my understanding as well. Or at least by prefixing with _ we have warned users this is an implementation detail (subject to change) that they shouldn't rely on.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jakirkham: this pre-dates me, so I defer. But if it's not documented somewhere we might want to review if that holds across the board. For me, _x is typically valid for subclassing by developers, otherwise it would be a __x. (i.e. public, protected, private in Java-parlance)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a Python thing generally (not specific to Zarr).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Single underscore if by far the most common thing to do, to show intent rather than enforce any privateness (which double underscore doesn't do either).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Comment threadzarr/core.py Outdated
check_array_shape('out', out, out_shape)

# iterate over chunks
if not hasattr(self.chunk_store, "getitems") or \

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ for removing hasattr hacks in general. 👍

madsbkand others added 2 commits October 7, 2022 15:27
Co-authored-by: Josh Moore <josh@openmicroscopy.org>
@github-actionsgithub-actionsBot added the needs release notes Automatically applied to PRs which haven't added release notes label Mar 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Resolved conflict.
I suggest we go with this approach for now and then unify get_partial_values() and getitems() later.

@rabernat

Copy link
Copy Markdown
Contributor

@joshmoore & @jakirkham - any objections to merging this as-is and deferring the broader discussions for future work?

@joshmoore

Copy link
Copy Markdown
Member

Thanks for the ping, @rabernat. I have to say I'm liking the typed Context better. I will read through again ASAP.

@martindurant

Copy link
Copy Markdown
Member

Notice the link to FITS reading: another example of per-chunk parameters that could be fixed by passing around a context, although it's not the only way to do it. I'd say that there are a number of efforts (some more and some less well developed) waiting to see what zarr will do.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

@joshmoore, how can I help progress here? Maybe an online meeting?

@joshmoore

Copy link
Copy Markdown
Member

Sorry, @madsbk. My last comment was shortly before leaving on several weeks of travel and I lost of track of this. It wasn’t my intention to hold you up, and big 👍 for the ping. A few thoughts (from smallest to biggest) though I get the feeling that you are being ping-ponged back and forth between design issues:

  • If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.
  • Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.
  • Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

@madsbk

Copy link
Copy Markdown
ContributorAuthor

If we're less than confident on this API, perhaps we should make this a keyword-only argument. That way the second position could potentially be used for something else and deprecation/renaming would be more straight-forward.

Agree, fixed.

Unlike some of the context that was going to get passed, I have the feeling that the meta_array is more likely to be used for all chunks equally. Does that sound right? If so, I'm a bit hesitant to force someone to create dictionaries of N objects all with the same meta_array instance wrapped in new Context object. As I started to think about "wildcard" keys in the context argument or an additional default_context argument, I realized that perhaps we've not gotten this abstract right yet.

I have added ConstantMap, which is a read-only map that maps all keys to the same constant value. This fixes the issue of having to create a Context for each key without complicating the semantic of getitems().

Finally, I've still not got a clear picture of what other fields on the Context object are going to help with the likes of partial read. Obviously, that's less to do your PR but just to callback to the original discussions about whether or not we knew what the API should look like.

I don't think any of us have a clear answer to this. Therefore, I suggest that we merge this PR and let people explore its possibilities. As long as Context is optional and we force Stores to implement a fallback if it doesn't exist, I think we are fine.

@rabernat
rabernat merged commit b14f15f into zarr-developers:mainApr 13, 2023
jakirkham added a commit that referenced this pull request Apr 13, 2023
@madsbk

Copy link
Copy Markdown
ContributorAuthor

Thanks all!

@rabernat

Copy link
Copy Markdown
Contributor

Thank you for your patience Mads.

@madsbkmadsbk mentioned this pull request Apr 18, 2023
@madsbk
madsbk deleted the getitems branch April 20, 2023 09:48
rapids-botBot pushed a commit to rapidsai/kvikio that referenced this pull request Jun 21, 2023
By using the new API in zarr-developers/zarr-python#1131, we do not have to guess whether to read into host or device memory. That is, no more filtering of specify keys like:
```python
if os.path.basename(fn) in [ zarr.storage.array_meta_key, zarr.storage.group_meta_key, zarr.storage.attrs_key, ]: ```
Notice, this PR is on hold until Zarr v2.15 is released Closes#119
UPDATE: Zarr v2.15 has been released
Authors:
- Mads R. B. Kristensen (https://github.com/madsbk)
Approvers:
- Lawrence Mitchell (https://github.com/wence-)
- Jordan Jacobelli (https://github.com/jjacobelli)
URL: #131
@jakirkhamjakirkham mentioned this pull request Jun 22, 2023
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs release notesAutomatically applied to PRs which haven't added release notes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@madsbk@quasiben@jakirkham@martindurant@joshmoore@rabernat