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

add MoveBucket to support moving a sub-bucket from one bucket to anot… #635

Merged
merged 4 commits into from
Jan 3, 2024

Conversation

Elbehery
Copy link
Member

This PR is a replacement to #625

cc @ahrtr @fuweid

bucket.go Show resolved Hide resolved
bucket.go Show resolved Hide resolved
@Elbehery Elbehery force-pushed the add_move_subBucket branch 3 times, most recently from 5157812 to f17b5b9 Compare December 12, 2023 14:29
@Elbehery
Copy link
Member Author

Elbehery commented Dec 12, 2023

WIP, needs

@Elbehery Elbehery force-pushed the add_move_subBucket branch 2 times, most recently from 9c40fa4 to 795773d Compare December 12, 2023 18:38
bucket_test.go Outdated Show resolved Hide resolved
@Elbehery
Copy link
Member Author

@ahrtr to follow up on testing this and according to #625 (comment)

i can use

func randKeys() [][]byte {
	var keys [][]byte
	var count = rand.Intn(2) + 2
	for i := 0; i < count; i++ {
		keys = append(keys, randKey())
	}
	return keys
}

func randValue() []byte {
	n := rand.Intn(8192)
	b := make([]byte, n)
	for i := 0; i < n; i++ {
		b[i] = byte(rand.Intn(255))
	}
	return b
}

to generate random keys & values .. also can generate random bucket depth and large keys & values as requested

would this be ok ?

@Elbehery
Copy link
Member Author

also @fuweid suggested #625 (comment)

this is another direction, please let me know

bucket_test.go Outdated Show resolved Hide resolved
bucket_test.go Outdated Show resolved Hide resolved
bucket_test.go Outdated Show resolved Hide resolved
tx_test.go Outdated Show resolved Hide resolved
@ahrtr
Copy link
Member

ahrtr commented Dec 13, 2023

The test case is big enough, suggest to get all MoveBucket related test cases defined in a separate file e.g. movebucket_test.go

@Elbehery
Copy link
Member Author

The test case is big enough, suggest to get all MoveBucket related test cases defined in a separate file e.g. movebucket_test.go

I separated the test into a separate file

i am stuck with dumping the bucket content into a file and comparing it, i will tag you on the code

movebucket_test.go Outdated Show resolved Hide resolved
bucket.go Outdated Show resolved Hide resolved
bucket.go Outdated Show resolved Hide resolved
@ahrtr
Copy link
Member

ahrtr commented Dec 14, 2023

The test case is big enough, suggest to get all MoveBucket related test cases defined in a separate file e.g. movebucket_test.go

I see that some tests are still in tx_test.go. Please get all moveBucket related test cases included in the new file.

@Elbehery Elbehery force-pushed the add_move_subBucket branch 4 times, most recently from 491ab6b to 1e7d3a0 Compare December 14, 2023 20:51
@Elbehery
Copy link
Member Author

@ahrtr @fuweid i finished the testing on Bucket layer

to do

  • refactor testing on tx layer
  • bucket content verification

@Elbehery
Copy link
Member Author

the failing test is not related to this change

=== RUN   ExampleTx_Rollback
--- PASS: ExampleTx_Rollback (0.01s)
=== RUN   ExampleTx_CopyFile
--- PASS: ExampleTx_CopyFile (0.01s)
FAIL
exit status 1
FAIL	go.etcd.io/bbolt	1202.726s
make: *** [Makefile:45: test] Error 1
Error: Process completed with exit code 2.

@ahrtr
Copy link
Member

ahrtr commented Dec 28, 2023

--- FAIL: TestTx_MoveBucket (4.45s)
    --- PASS: TestTx_MoveBucket/happy_path (0.60s)
    --- PASS: TestTx_MoveBucket/bucketToMove_not_exist_in_srcBucket (0.40s)
    --- PASS: TestTx_MoveBucket/bucketToMove_exist_in_dstBucket (0.48s)
    --- PASS: TestTx_MoveBucket/bucketToMove_key_exist_in_srcBucket,_but_no_subBucket_value (0.31s)
    --- PASS: TestTx_MoveBucket/bucketToMove_key_exist_in_dstBucket,_but_no_subBucket_value (0.16s)
    --- PASS: TestTx_MoveBucket/srcBucket_is_rootBucket (0.38s)
    --- PASS: TestTx_MoveBucket/dstBucket_is_rootBucket (0.19s)
    --- PASS: TestTx_MoveBucket/srcBucket_is_rootBucket,_and_dstBucket_is_rootBucket (0.14s)

@Elbehery
Copy link
Member Author

@ahrtr it is the cleanUp on Windows :/

    testing.go:1206: TempDir RemoveAll cleanup: remove C:\Users\RUNNER~1\AppData\Local\Temp\TestTx_MoveBucket2465631041\002\beforeBucket.db: Access is denied.

@Elbehery
Copy link
Member Author

this should have been fixed in golang/go#50051

the fix is retrying to remove using this

/ removeAll is like os.RemoveAll, but retries Windows "Access is denied."
// errors up to an arbitrary timeout.
//
// Those errors have been known to occur spuriously on at least the
// windows-amd64-2012 builder (https://go.dev/issue/50051), and can only occur
// legitimately if the test leaves behind a temp file that either is still open
// or the test otherwise lacks permission to delete. In the case of legitimate
// failures, a failing test may take a bit longer to fail, but once the test is
// fixed the extra latency will go away.
func removeAll(path string) error {

two option, either I fall back to tempFile() from bbolt testing, or rerun the test and hope :D

@ahrtr
Copy link
Member

ahrtr commented Dec 28, 2023

Note that we have lots of usage of t.TempDir() in the test, we have never seen this issue on the master/main branch so far. Also the golang issue you mentioned had already been fixed in go 1.18. Can you figure out the root cause?

}
}

func createBucketIfNotExist(t testing.TB, tx *bbolt.Tx, incompatibleKey bool, paths ...string) *bbolt.Bucket {
Copy link
Member

Choose a reason for hiding this comment

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

In the example in #635 (comment), the parameter paths should be [sb1, sb2] or [db1, db2]

Suggested change
func createBucketIfNotExist(t testing.TB, tx *bbolt.Tx, incompatibleKey bool, paths ...string) *bbolt.Bucket {
func openBuckets(t testing.TB, tx *bbolt.Tx, paths ...string) *bbolt.Bucket {

The high level algorithm is something like below,

  • Create the bucket hirarchy structure
    • if incompatibleKeyInSrc is true, then create a normal key; otherwise, create a sub-bucket
    • the same thing for the incompatibleKeyInDst
  • Move the bucket
    • open the bucket: reuse openBuckets
    • call tx.MoveBucket(key, srcBucket, dstBucket)
  • Verify

Copy link
Member Author

Choose a reason for hiding this comment

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

done

movebucket_test.go Outdated Show resolved Hide resolved
@Elbehery Elbehery force-pushed the add_move_subBucket branch 2 times, most recently from 33bcf3b to 8e38c33 Compare December 28, 2023 22:57
@Elbehery
Copy link
Member Author

Note that we have lots of usage of t.TempDir() in the test, we have never seen this issue on the master/main branch so far. Also the golang issue you mentioned had already been fixed in go 1.18. Can you figure out the root cause?

yes i see many times in the code it uses it exactly as I do

filepath.Join(t.TempDir(), "db")

i really dont know why it fails now, the issue is access denied, somehow the cleanUp routine can not access the file :/

ahrtr and others added 2 commits January 2, 2024 14:33
…her bucket

Signed-off-by: Benjamin Wang <benjamin.ahrtr@gmail.com>
Signed-off-by: Mustafa Elbehery <melbeher@redhat.com>
Signed-off-by: Benjamin Wang <benjamin.ahrtr@gmail.com>
Signed-off-by: Benjamin Wang <benjamin.ahrtr@gmail.com>
@ahrtr
Copy link
Member

ahrtr commented Jan 2, 2024

Talked with @Elbehery in today's meeting, and I added two commits in this PR.

Please take a look, and let me know if you have any comment on this PR. @fuweid @Elbehery

Note I also manually verified the new functionality, and confirmed that it is working as expected.

Copy link
Member

@fuweid fuweid left a comment

Choose a reason for hiding this comment

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

LGTM

}
}()

if b.tx.db == nil || dstBucket.tx.db == nil {
Copy link
Member

Choose a reason for hiding this comment

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

It seems like we should limit both src and dst are in that same db.

Copy link
Member

@ahrtr ahrtr Jan 3, 2024

Choose a reason for hiding this comment

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

yes, it's a good point.

We can add protection something like below in (*Bucket)MoveBucket,

	if b.tx.db.Path() != dstBucket.tx.db.Path() || b.tx != dstBucket.tx {
		// return error
	}

We also need to add a test

@Elbehery can you take care of it in a following up PR?

@ahrtr ahrtr merged commit 19be273 into etcd-io:main Jan 3, 2024
15 checks passed
@ahrtr ahrtr added this to the v1.4.0 milestone Jan 3, 2024
@Elbehery Elbehery deleted the add_move_subBucket branch January 12, 2024 20:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging this pull request may close these issues.

None yet

3 participants