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

initial implementation of 3to4 migration #39

Merged
merged 14 commits into from
Jul 1, 2016
Merged

Conversation

whyrusleeping
Copy link
Member

No description provided.

@kevina
Copy link
Contributor

kevina commented Jun 28, 2016

@whyrusleeping I am not sure what stage this is at, but as far as transferring the blocks I can think of two important optimizations that may be worth implementing:

  1. It should be possible to tell if a block key is not managed by checking if the key is the expected length. If it was managled in some way it would be shorter. This will avoid the cost of recomputing the hash.

  2. Although this will brake abstraction the file respecting a blocks could simply be renamed. When combined with (1) this could lead to a large (at least an order of magnitude) speed up.

I could probably implement these in a day if you want and you think they are worth implementing. Let me know.

@whyrusleeping
Copy link
Member Author

  1. It should be possible to tell if a block key is not managed by checking if the key is the expected length. If it was managled in some way it would be shorter. This will avoid the cost of recomputing the hash.

I'm not worried about that. I don't really mind the cost of re-hashing all the blocks, as it may help catch any potential corruption issues that might have occurred.

  1. Although this will brake abstraction the file respecting a blocks could simply be renamed. When combined with (1) this could lead to a large (at least an order of magnitude) speed up.

I considered that, the issue with breaking the abstractions is that we have a lot of edge casing in the code (especially related to renaming files across different platforms and filesystem boundaries)

@kevina
Copy link
Contributor

kevina commented Jun 28, 2016

  1. Although this will brake abstraction the file respecting a blocks could simply be renamed. When combined with (1) this could lead to a large (at least an order of magnitude) speed up.

I considered that, the issue with breaking the abstractions is that we have a lot of edge casing in the code (especially related to renaming files across different platforms and filesystem boundaries)

Maybe we can provide a '--fast' option that could abort if an edge case is detected? In any case this is something that could be done a bit later if the need arises. For now I would agree it is more important to get something simple that works.

As a side note (and no need to respond), avoiding the renaming is also one of the reason I originally wanted to preserve the hex encoding in the file names of the flatfs.

@whyrusleeping
Copy link
Member Author

@Kubuxu the tests are failing right now because the ipfs init with 0.4.3-dev is printing 'Error: EOF' for some reason. I havent looked too deeply, but i'm tired and maybe you can figure it out while i'm sleeping.

@Kubuxu
Copy link
Member

Kubuxu commented Jun 29, 2016

@whyrusleeping I am away for the bigger part of today.

@whyrusleeping
Copy link
Member Author

@Kubuxu no worries then

@kevina
Copy link
Contributor

kevina commented Jun 29, 2016

@whyrusleeping for completeness I image we should make sure that a few of the datastore entries migrated in the test are effected by the key.Clean bug. Apologies if this was already done.

This might be more important if we decide to implement an optimized migration path as I outlined above.

@whyrusleeping
Copy link
Member Author

@kevina good point. One easy way to do that would be to manually add one we know to have that bug. I'll try and find a small file that has the issue.

@kevina
Copy link
Contributor

kevina commented Jun 29, 2016

@whyrusleeping Here are a few from ipfs/kubo#994 thanks to @Cleric-K comment:

  1. Slash at the end. Test with $ echo 10 | ipfs add

  2. Two or more slashes (get converted to one slash). $ echo 00000259 | ipfs add

  3. /../ - removes the part before that token. $ echo 0243397916 | ipfs add. Creates file:
    d83220a26feced8c55f3ede2819a7f0a84ce.data
    instead of:
    12200bf25b81d5a2ab229b652f2e2e2fd83220a26feced8c55f3ede2819a7f0a84ce.data

    I image the test cases will dig some more up.

@whyrusleeping
Copy link
Member Author

the strings: ba bbd and cdbd currently trigger the bug when added as files

@whyrusleeping
Copy link
Member Author

as well as aabdb adbdc bccac and dacab (I can keep going, but this should be plenty)

@whyrusleeping
Copy link
Member Author

@kevina any other edge cases you think we should test?

@kevina
Copy link
Contributor

kevina commented Jun 29, 2016

@whyrusleeping, not off hand.

@whyrusleeping
Copy link
Member Author

@kevina changed the blocks rewriting to just rename if it can.

@ghost
Copy link

ghost commented Jul 1, 2016

Got any estimate how long this will take on a certain 16 TB spinning-disks host?

@whyrusleeping
Copy link
Member Author

@lgierth much less time now :P

With the current rename changes, probably within a 10x overhead from the time to do an 'ipfs refs local'

@kevina
Copy link
Contributor

kevina commented Jul 1, 2016

@whyrusleeping looks good

@kevina
Copy link
Contributor

kevina commented Jul 1, 2016

@whyrusleeping, one other think I thought of, since this is something that could take a while, what would happen if the process was interrupted. Will it just continue where it left off when restarted?

If not, although I don't see how this could corrupt the repo, I could see how it could leave it in a bad state that will require special care to fix.

@whyrusleeping
Copy link
Member Author

@kevina if the process gets interrupted everything should be fine. We only transfer keys that match the format we're expecting, so any keys that have already been moved will be skipped.

@kevina
Copy link
Contributor

kevina commented Jul 1, 2016

@whyrusleeping I see that now that what testing for the "1220" prefix is for.

Note that it is possible for a key to be so badly managed that it doesn't start with "1220" and will thus be skipped. For example echo 0243397916 | ipfs add, from an earlier comment, would create the fiile "d83220a26feced8c55f3ede2819a7f0a84ce.data".

I would add a pass at the end two to do two things:

  1. Verify that all files in the datastore are now base32 encoded (try to decode the key) and the correct length and report any errors.
  2. Remove empty directories.

@whyrusleeping
Copy link
Member Author

@kevina ah! interesting. The binary key for that value contians the sequence /../

I'll add a test for that

@whyrusleeping
Copy link
Member Author

@kevina there we go, added that as a test case. We no longer assume anything about the key. We will only skip a key if it matches the exact base32 format, or if it doesnt have a .data suffix

}

cdir := filepath.Join(dir, c.Name())
blocks, err := ioutil.ReadDir(cdir)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: File.Readdirnames would be a better choice. ioutil.ReadDir will perform a stat on each directory entry and then sort them by name. Not sure if it really matters so fell free to ignore.

Copy link
Member

Choose a reason for hiding this comment

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

There are only few files in most dirs at a time, but using that instead wouldn't hurt in case of big repos.

Copy link
Member Author

Choose a reason for hiding this comment

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

@kevina I actually dont think it calls stat individually on each one. take a look at the go source in os/dir_unix.go

Copy link
Contributor

Choose a reason for hiding this comment

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

@whyrusleeping the file you pointed me to only contains an implementation for readdirnames, readdir is implemeted in os/file_unix.go and it actually calls Readdirnames first and than calls lstat for each entry. I don't see how it could be implemented any other way because of how the related system calls on unix work.

@Kubuxu
Copy link
Member

Kubuxu commented Jul 1, 2016

LGTM

@whyrusleeping
Copy link
Member Author

alright, choo choo

@whyrusleeping whyrusleeping merged commit fc46b58 into master Jul 1, 2016
@whyrusleeping whyrusleeping deleted the feat/3-to-4 branch July 1, 2016 20:59
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.

3 participants