Skip to content

List oids null#663

Merged
mergify[bot] merged 2 commits intoceph:masterfrom
nickjanus:list_oids_null
Apr 21, 2022
Merged

List oids null#663
mergify[bot] merged 2 commits intoceph:masterfrom
nickjanus:list_oids_null

Conversation

@nickjanus
Copy link
Contributor

👋 We've been using a patch that's similar to this in production for a while now, which has helped with our internal tooling to clean up broken MPUs created by RGW. Ideas welcome on how I could go about testing the changes to ListObjects. I don't know of a way to create an object with a null char in the key short of getting a new CLS function committed.

Checklist

  • Added tests for features and functional changes
  • Public functions and types are documented
  • Standard formatting is applied to Go code
  • Is this a new API? Is this new API marked PREVIEW?

Copy link
Collaborator

@phlogistonjohn phlogistonjohn left a comment

Choose a reason for hiding this comment

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

Thank you very much for your contribution! I have a few comments below. Overall, it looks like a nice improvement.

"empty": []byte(""),
"key1": []byte("value1"),
"key2": []byte("value2"),
"prefixed\x00key3": []byte("value3"),
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'd prefer to see the new key in addition to the existing key, thanks.

rados/ioctx.go Outdated
ret := C.rados_nobjects_list_open(ioctx.ioctx, &ctx)
if ret < 0 {
return getError(ret)
page_results := C.size_t(1000)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Since this is a "magic" value. Let's make it a const at the file level. Name it something like defaultListObjectsResultSize.

rados/ioctx.go Outdated

next := C.rados_object_list_begin(ioctx.ioctx)
if next == nil {
return errors.New("Pool does not exist")
Copy link
Collaborator

Choose a reason for hiding this comment

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

It might be better to return ErrNotFound here.

rados/ioctx.go Outdated
listFn(C.GoStringN(item.oid, (C.int)(item.oid_length)))
}

if ret := C.rados_object_list_is_end(ioctx.ioctx, next); int(ret) == 1 {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Again, it would make things clearer to have the "magic" value 1 as a real constant such as const listEndSentinel = C.int(1). Also, since ret isn't used elsewhere again there's no need to assign ret, just do:

if C.rados_object_list_is_end(...) == listEndSentinel {
...
}

@phlogistonjohn
Copy link
Collaborator

Regarding the tests, are there no functions in go-ceph that currently allow you to create the object name with a null? I'm not clear what a "CLS function" is.

@nickjanus
Copy link
Contributor Author

re testing: Sorry, I'm probably not using the correct terminology, I meant an OSD class method (https://docs.ceph.com/en/latest/rados/api/librados/#c.rados_exec). From the librados documentation, I don't see how to specify an oid with a length, so that it can include a null character. I had assumed that this was only possible using some osd class method, but maybe I'm missing something.

@phlogistonjohn
Copy link
Collaborator

re testing: Sorry, I'm probably not using the correct terminology, I meant an OSD class method (https://docs.ceph.com/en/latest/rados/api/librados/#c.rados_exec).

OK, thanks. I was vaguely aware of that method but don't know much about it.

From the librados documentation, I don't see how to specify an oid with a length, so that it can include a null character.

I just skimmed the list of function definitions and I agree, there's nothing obvious there to create a name with a null. Obviously, it must be possible since you're seeing them. However, it may be done at a layer "below" librados and therefore difficult to access via go-ceph.

I had assumed that this was only possible using some osd class method, but maybe I'm missing something.

Maybe, if you research it and find it is possible that way, I'd certainly be open to having something like rados_write_op_exec and/or rados_exec to the library. I am somewhat concerned that it may not do what you want as the inline docs say "The OSD has a plugin mechanism for performing complicated
operations on an object atomically" and const char *oid is in the function defintion. Both imply that the name of the object is supplied as a null-terminated string up front.

Another approach you might take is to ask the RGW developers how it was done (regardless of if it was indented).

Finally, while I'd like to have regression tests for everything, I'd be fine not having coverage for this case and still taking these patches. The existing test will cover the common use case. So don't worry about the patches being declined just for the lack of a test for the "extra nulls" case.

Copy link
Collaborator

@phlogistonjohn phlogistonjohn left a comment

Choose a reason for hiding this comment

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

It looks like you may have overlooked make check failing when you updated the patches based on my earlier feedback. New code should have typical golang naming standards (no underscores).

Additionally, there's still a "bare 1" rather than a listEndSentinel. Since this is a suggestion, not a requirement, feel free to say if you don't want to do that. At the moment though, I don't know if you forgot or chose not to do that.

@nickjanus
Copy link
Contributor Author

It looks like you may have overlooked make check failing when you updated the patches based on my earlier feedback. New code should have typical golang naming standards (no underscores).

Additionally, there's still a "bare 1" rather than a listEndSentinel. Since this is a suggestion, not a requirement, feel free to say if you don't want to do that. At the moment though, I don't know if you forgot or chose not to do that.

I'll fix up the formatting, and that was an oversight on my part, so I'll replace with a non-magic value, thanks for the review! I should be able to push an updated branch this evening.

@nickjanus
Copy link
Contributor Author

It looks like there a test failure when iterating over an omap with a iteratorSize of 1. Going to play around with the new null char key to see if that ordering makes a difference and debug from there.

@phlogistonjohn Do you think it would be valuable to have a make command that ran tests in a docker container with a given ceph version's packages installed?

@phlogistonjohn
Copy link
Collaborator

It looks like there a test failure when iterating over an omap with a iteratorSize of 1. Going to play around with the new null char key to see if that ordering makes a difference and debug from there.

Sounds reasonable.

@phlogistonjohn Do you think it would be valuable to have a make command that ran tests in a docker container with a given ceph version's packages installed?

I'm not sure what you mean by "a given ceph version's packages installed". If you just mean trying out different major version of ceph you should already be able to do that. Some examples:

make test-containers-test CEPH_VERSION=nautilus
make test-containers-clean # teardown

make test-containers-test CEPH_VERSION=octopus
make test-containers-clean # teardown

make test-containers-test CEPH_VERSION=pacific
make test-containers-clean # teardown

Everything the CI does should be doable on one's desktop/laptop.

You can narrow down the scope of what's being tested too. To run only a particular sub-package of go-ceph use ENTRYPOINT_ARGS=''--test-pkg=rados" for example: make test-containers-test CEPH_VERSION=octopus ENTRYPOINT_ARGS='--test-pkg=rados'

You can even make custom containers to use, but doing so is not direct or easy. If I'm misunderstanding your request, please feel free to correct me.

@nickjanus
Copy link
Contributor Author

Ah nope, that's exactly what I was asking about, thanks! I hadn't looked at the existing Makefile closely enough.

@phlogistonjohn
Copy link
Collaborator

There's https://github.com/ceph/go-ceph/blob/master/docs/development.md#testing too. but I forgot to link to it earlier. Also don't hesitate to file issues if the above docs are wrong/incomplete or you simply want to request that we document something!

@nickjanus
Copy link
Contributor Author

Looks like the test failure is just a limitation of librados - start_after is a c string, so listing will end early if a key has a null char and max_return is too small.

@nickjanus
Copy link
Contributor Author

This should be ready for CI again.

@nickjanus
Copy link
Contributor Author

👋 The test failure for Pacific looks unrelated to these commit. Let me know if there's any other changes I should make, and thanks for looking!

Copy link
Collaborator

@phlogistonjohn phlogistonjohn left a comment

Choose a reason for hiding this comment

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

Looks good to me. Just because it's a bit of a subtle bunch of changes I would like a 2nd reviewer to look at it. That's the only reason for the dnm label at this time.

@ansiwen PTAL and remove the 'do-not-merge' label if you approve. Thanks!

Copy link
Collaborator

@ansiwen ansiwen left a comment

Choose a reason for hiding this comment

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

Well, I don't like the rados_object_list API, but that's not the faut of this PR. ;-) (Why you have use a finish cursor, if you anyway have to check for the end of the list with ..._is_end? 🙄 )

@phlogistonjohn
Copy link
Collaborator

@Mergifyio rebase

Nick Janus added 2 commits April 21, 2022 13:44
The previous `rados_nobjects_list_open` used for listing could not
return oids that included null characters. Although this isn't a common
case, having go-ceph able to list such objects is useful for bugs such
as https://tracker.ceph.com/issues/48874.

Signed-off-by: Nick Janus <github@nondesignated.com>
Previous changes added support for operating on omap keys that include
null characters (e.g. rados_omap_get_next2,
rados_write_op_omap_rm_keys2).  This change adds some basic test
coverage those operations' null character support.

Signed-off-by: Nick Janus <github@nondesignated.com>
@mergify
Copy link

mergify bot commented Apr 21, 2022

rebase

✅ Branch has been successfully rebased

@phlogistonjohn
Copy link
Collaborator

@Mergifyio requeue

@mergify
Copy link

mergify bot commented Apr 21, 2022

requeue

❌ This pull request head commit has not been previously disembarked from queue.

@phlogistonjohn phlogistonjohn added the no-API This PR does not include any changes to the public API of a go-ceph package label Apr 21, 2022
@mergify mergify bot merged commit e1f75a4 into ceph:master Apr 21, 2022
@nickjanus nickjanus deleted the list_oids_null branch April 22, 2022 18:01
@nickjanus
Copy link
Contributor Author

Thanks, folks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-API This PR does not include any changes to the public API of a go-ceph package

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants