Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP]: Initial ObjectStore client implementation #331

Merged
merged 23 commits into from
Jun 1, 2023

Conversation

domderen
Copy link
Contributor

This pull request contains a JetStream ObjectStore client implementation. It is an early draft that at the moment contains following functionalities:

  • Create Object Store,
  • Get Object Store,
  • Delete Object Store,
  • Put Object,
  • Get Object,

It was re-implemented from the golang code in nats.go repo.

This code is not complete yet! I'm sharing it in this form to gather some initial feedback if this is the right direction for this implementation. Any feedback is welcome :)

I think it would be good to implement ObjectStore calls around Bytes.IO types, to allow handling streams, same as the golang version does, but I went with simpler bytes implementation for now. I can try to extend it later on if it will look like a right direction.

wallyqs and others added 13 commits November 11, 2020 12:26
When a NATS Server restarted behind an LB, reconnection
would fail since the proper connect timeout exception was not
being caught, leaving the client hanging sometimes.

Signed-off-by: Waldemar Quevedo <wally@synadia.com>
Signed-off-by: Waldemar Quevedo <wally@synadia.com>
Signed-off-by: Waldemar Quevedo <wally@synadia.com>
Fix issue when reconnecting against LB
…ze-option

Support set pending size to client connect options
Bumps [py](https://github.com/pytest-dev/py) from 1.8.0 to 1.10.0.
- [Release notes](https://github.com/pytest-dev/py/releases)
- [Changelog](https://github.com/pytest-dev/py/blob/master/CHANGELOG.rst)
- [Commits](pytest-dev/py@1.8.0...1.10.0)

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Waldemar Quevedo <wally@synadia.com>
Removed loop from options, deprecated from nats.connect().
@domderen
Copy link
Contributor Author

Hey @wallyqs it would be great to hear your thoughts on this PR.

@wallyqs
Copy link
Member

wallyqs commented Aug 24, 2022

Thanks @domderen for the contribution and the rebase. Sorry for the delay, I will start looking today.

Copy link

@tothandras tothandras left a comment

Choose a reason for hiding this comment

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

I've started to check the cross language compatibility of the implementations, first with Go and I plan to do the same with JavaScript.
(I have a use case where I write objects in Python and read them from JavaScript.)


data = None
if msg.data:
data = base64.b64decode(msg.data)
Copy link

Choose a reason for hiding this comment

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

Suggested change
data = base64.b64decode(msg.data)
data = msg.data.decode()

nats/js/object_store.py Show resolved Hide resolved
nats/js/api.py Outdated Show resolved Hide resolved
)
raise e

info.mtime = datetime.utcnow().timestamp()

Choose a reason for hiding this comment

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

Suggested change
info.mtime = datetime.utcnow().timestamp()
info.mtime = datetime.now(timezone.utc).isoformat()

nuid=id.decode(),
size=0,
chunks=0,
mtime=0

Choose a reason for hiding this comment

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

from datetime import datetime, timezone
# ...
Suggested change
mtime=0
mtime=datetime.now(timezone.utc).isoformat(),


# Make sure the digest matches.
sha = h.digest()
digest_str = info.digest.replace(OBJ_DIGEST_TYPE, "")

Choose a reason for hiding this comment

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

Suggested change
digest_str = info.digest.replace(OBJ_DIGEST_TYPE, "")
digest_str = info.digest.replace(OBJ_DIGEST_TYPE, "").replace(OBJ_DIGEST_TYPE.upper(), "")

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hey, could you elaborate, why somthing like this?

Copy link

@tothandras tothandras Oct 7, 2022

Choose a reason for hiding this comment

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

Comment on lines 143 to 148
obj = self.__sanitize_name(name)

if not key_valid(obj):
raise InvalidObjectNameError

meta = OBJ_META_PRE_TEMPLATE.format(bucket=self._name, obj=obj)

This comment was marked as outdated.

if not key_valid(obj):
raise InvalidObjectNameError

meta = OBJ_META_PRE_TEMPLATE.format(bucket=self._name, obj=obj)
Copy link

Choose a reason for hiding this comment

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

See: https://github.com/nats-io/nats.go/blob/f4102422df7df83b2032318fd14a248c45f113e1/object.go#L442

Suggested change
meta = OBJ_META_PRE_TEMPLATE.format(bucket=self._name, obj=obj)
meta = OBJ_META_PRE_TEMPLATE.format(bucket=self._name, obj=base64.urlsafe_b64encode(bytes(obj, "utf-8")).decode().rstrip("="))

chunk_subj = OBJ_CHUNKS_PRE_TEMPLATE.format(
bucket=self._name, obj=id.decode()
)
meta_subj = OBJ_META_PRE_TEMPLATE.format(bucket=self._name, obj=obj)
Copy link

Choose a reason for hiding this comment

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

Suggested change
meta_subj = OBJ_META_PRE_TEMPLATE.format(bucket=self._name, obj=obj)
meta_subj = OBJ_META_PRE_TEMPLATE.format(bucket=self._name, obj=base64.urlsafe_b64encode(bytes(obj, "utf-8")).decode().rstrip("="))

@domderen
Copy link
Contributor Author

Hey @tothandras thanks for your comments. I'm on holidays at the moment, but will look into it once I'm back in ~2 weeks.

@tothandras
Copy link

@domderen enjoy your holiday!

@domderen
Copy link
Contributor Author

domderen commented Oct 5, 2022

Hey @tothandras I updated this PR with your comments. I think I included them all, but would you mind taking a look?

@tothandras
Copy link

@domderen If you could rebase on master I could try it out. I'm probably less suited for reviewing the code itself. I lack the deep knowledge of Python. :)

@domderen
Copy link
Contributor Author

domderen commented Oct 8, 2022

Hey I think the rebase should be done, though I'm not sure if I didn't mess something up... Looks like a lot of changes now...

@wallyqs
Copy link
Member

wallyqs commented Oct 8, 2022

@domderen I think you can try something like the following below to squash into a single commit and avoid the merge conflicts using your current branch:

# Checkout the object store branch
git checkout object_store

# Take a diff against latest main, we'll apply this diff as a patch.
git diff main > obj.diff

# Rename current local object_store branch.
git branch -m object-store-backup

# Redo object_store branch
git checkout main
git branch object_store
git checkout object_store

# Apply the diff as a patch on top of object_store branch and commit.
git apply -3 obj.diff

# Fix formatting
make format

git commit -s -m "Add Object Store implementation"

# Force push the object_store branch that is now squashed and rebased.
git push main object_store -f

I gave it a try at squashing into a single commit via a diff the result can be found here: https://github.com/nats-io/nats.py/compare/obj
When running the tests I'm running into a binascii.Error: Incorrect padding error though:
https://app.travis-ci.com/github/nats-io/nats.py/jobs/585091380#L508

@tothandras
Copy link

I just run into an issue with __sanitize_name, we should definitely write some integration tests to make sure all language implementations are compatible with each other. I hope to have time for it in the next 2-3 weeks.

Signed-off-by: Dominik Deren <dominik.deren@live.com>
@domderen
Copy link
Contributor Author

domderen commented Oct 9, 2022

Hey @wallyqs thanks for the help! I followed your steps and force pushed just those changes that looked like my original implementation. It should make it easier to review. Let's see if the build passes now, if not I'll take a look at tests.

@domderen
Copy link
Contributor Author

domderen commented Oct 9, 2022

@tothandras I think I tried to take this implementation of __sanitize_name from the golang implementation. Are they different now?

@domderen
Copy link
Contributor Author

domderen commented Oct 9, 2022

Hmm there are two tests failing, but those are two different tests in two different builds, both don't seem to be related to my changes... Should I expect some flakiness in those tests?

@tothandras
Copy link

@tothandras I think I tried to take this implementation of __sanitize_name from the golang implementation. Are they different now?

Sorry, I was wrong. It seems I didn't apply all the patches on my fork.

@danielfernandez-igz
Copy link

Hi everyone!

Are there any plans to resume this PR in the short term? I noticed it was reviewed six months ago, but has been stale for some time now.

Also, looks like the Travis build failed due to a flaky test but it's been excluded from pytest runs, so it shouldn't be a concern anymore (see #424).

Thank you all!

@domderen
Copy link
Contributor Author

domderen commented Mar 7, 2023

Hey, I was updating this PR occasionally when I needed to change something in the Object Store implementation for my own needs. I'm happy to keep going on this PR, but I'm not sure if owners see it as valuable, or if they would prefer a different direction.

It is also still missing some of the APIs that Object Store has in golang version, and I'm not sure what would be the minimal required scope for it to get merged.

@wallyqs wallyqs merged commit 1daa0ca into nats-io:main Jun 1, 2023
@domderen domderen deleted the object_store branch March 6, 2024 08:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants