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

Serializing bitseq alloc #1788

Merged
merged 3 commits into from
Oct 3, 2017
Merged

Serializing bitseq alloc #1788

merged 3 commits into from
Oct 3, 2017

Conversation

abhi
Copy link
Contributor

@abhi abhi commented May 31, 2017

Previously the bitseq alloc was allocating the first available bit from the beginning of the bit sequence for each sequence handle. With this commit the bitseq alloc will proceed
from the current allocation. This change will affect the way ipam and vni
allocation is done currently. The ip allocation will prcoeeed sequentially from the previous allocation as opposed to the first available IP. So even if the IPs are released it will not be reused until the allocator rolls over to the beginner of the bit sequence.

The commit also contains a fix for byteoffset allocation which plays a role in calculating the allocated ordinal. This scenerio play when the starting ordinal is part of the head sequence block and the available bit is part of subsequent blocks in the bitseq.

Signed-off-by: Abhinandan Prativadi abhi@docker.com

@abhi abhi changed the title Serializing bitseq alloc [Not Ready for Review ] Serializing bitseq alloc May 31, 2017
@abhi abhi force-pushed the ipam_alloc branch 4 times, most recently from c043f63 to 62472f3 Compare June 5, 2017 05:33
@abhi abhi changed the title [Not Ready for Review ] Serializing bitseq alloc Serializing bitseq alloc Jun 5, 2017
@@ -511,6 +513,29 @@ func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
return invalidPos, invalidPos, ErrNoBitAvailable
}

//getAvailableFromCurrent will look for available ordinal from the current ordinal.

Choose a reason for hiding this comment

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

space missing

Copy link
Contributor Author

Choose a reason for hiding this comment

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

will make change

@@ -511,6 +513,29 @@ func getFirstAvailable(head *sequence, start uint64) (uint64, uint64, error) {
return invalidPos, invalidPos, ErrNoBitAvailable
}

//getAvailableFromCurrent will look for available ordinal from the current ordinal.
// If none found then it will loop back to the start to check of the available bit.
//This can be further optimized to check from start till curr in case of a rollover

Choose a reason for hiding this comment

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

space missing

if end < ret {
err = ErrNoBitAvailable
if err == nil {
h.curr = ret + 1

Choose a reason for hiding this comment

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

when the last bit is allocated is there the risk that doing the +1 the number wraps to 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

that will result in failure and cause the allocation from the start=

//This can be further optimized to check from start till curr in case of a rollover
func getAvailableFromCurrent(head *sequence, start, curr, end uint64) (uint64, uint64, error) {
var bytePos, bitPos uint64
if curr != 0 && curr > start {

Choose a reason for hiding this comment

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

is it necessary curr != 0? is it not the same as the starting case where start == 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

but start need not be 0 . but curr could be if not allocated yet

bytePos, bitPos, _ = getFirstAvailable(head, curr)
ret := posToOrdinal(bytePos, bitPos)
if end < ret {
goto begin

Choose a reason for hiding this comment

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

you don't really need a goto here.
If start < ret < end then the result is valid and you can return the result. Else you continue you just continue with the other lookup

Copy link
Contributor Author

Choose a reason for hiding this comment

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

avoding multiple condition in if. IMO this would be cleaner.

@@ -939,9 +941,6 @@ func TestAllocateRandomDeallocate(t *testing.T) {
if hnd.Unselected() != uint64(numBits/2) {
t.Fatalf("Expected half sequence. Instead found %d free bits.\nSeed: %d\n%s", hnd.unselected, seed, hnd)
}
if !hnd.head.equal(expected) {

Choose a reason for hiding this comment

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

Is this a check that we may still want to have to validate the consistency of the allocation?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Allocation not be part of the head. So this verification will not hold true with new change.

idm/idm_test.go Outdated
@@ -110,7 +110,7 @@ func TestUninitialized(t *testing.T) {
}

func TestAllocateInRange(t *testing.T) {
i, err := New(nil, "myset", 5, 10)
i, err := New(nil, "myset", 5, 12)

Choose a reason for hiding this comment

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

is there a reason to change this test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yes since the allocation is serial and not the first available expanding the range to suit the test

for current != nil {
if current.block != blockMAX {
bytePos, bitPos, err := current.getAvailableBit(bitOffset)
return byteOffset + bytePos, bitPos, err
}
// Moving to next block: Reset bit offset.
bitOffset = 0
byteOffset += current.count * blockBytes
byteOffset += (current.count * blockBytes) - firstOffset

Choose a reason for hiding this comment

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

so is this because the current.count of the first byte is not 0?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

its because the offset is already calculated and we readd the whole node block count here. This is effective only in scenario where the start is not the from 0 byte and its part of the head RLE node

Choose a reason for hiding this comment

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

sorry maybe I'm missing something but if it is part of the head, the current.count should not equal to 0 and so the byteOffset is not modified by the original code?

@trapier
Copy link
Collaborator

trapier commented Sep 21, 2017

Have not reviewed the code, but very much like the concept. This will provide the gossip control plane maximum time to settle during task churn.

@fcrisciani
Copy link

@trapier gossip control plane is a transportation mean, does not take any decision on IP matter also the key of every element is the endpoint ID that is unique.
The underlying issue that brings potential IP overlap is due to how swarmkit handles resources, allowing the IP reuse also when a task is in the process to shutdown but still active and running

@trapier
Copy link
Collaborator

trapier commented Sep 22, 2017

Understood @fcrisciani. What I was thinking is if there are many joins and leaves occurring at the same time on a particular network (and despite the fact that it has a lamport clock), numerically ordered ip allocation will reduce the likelihood of same-time same-address events on the control plane.

@fcrisciani
Copy link

@trapier sure, but the problem would be in the application layer, because from a networkdb point of view each single event will have a different endpoint ID so a different key and no collision would be possible

Copy link
Contributor

@mavenugo mavenugo left a comment

Choose a reason for hiding this comment

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

Minor Comment. LGTM otherwise.

Can you pls address all other open comments ?


// AllocSerialPrefix constant marks the reserved label space for libnetwork ipam
// allocation ordering.(serial/first available)
AllocSerialPrefix = Prefix + ".serial"
Copy link
Contributor

Choose a reason for hiding this comment

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

can you pls make this .ipam.serial

@mavenugo
Copy link
Contributor

@abhi ping

@fcrisciani are you good with this change ?

Previously the bitseq alloc was allocating the first available bit from the
begining of the sequence. With this commit the bitseq alloc will proceed
from the current allocation. This change will affect the way ipam and vni
allocation is done currently. The ip allocation will be done sequentially
from the previous allocation as opposed to the first available IP.

Signed-off-by: Abhinandan Prativadi <abhi@docker.com>
Since bit allocation is no longer first available from
the start some verfications are removed/modified to
the change allocation model

Signed-off-by: Abhinandan Prativadi <abhi@docker.com>
@codecov-io
Copy link

codecov-io commented Sep 29, 2017

Codecov Report

❗ No coverage uploaded for pull request base (master@7447e54). Click here to learn what that means.
The diff coverage is 97.77%.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #1788   +/-   ##
=========================================
  Coverage          ?   38.02%           
=========================================
  Files             ?      137           
  Lines             ?    27313           
  Branches          ?        0           
=========================================
  Hits              ?    10386           
  Misses            ?    15656           
  Partials          ?     1271
Impacted Files Coverage Δ
drivers/overlay/ov_network.go 0.25% <0%> (ø)
bitseq/store.go 64.89% <100%> (ø)
ipam/allocator.go 69.33% <100%> (ø)
bitseq/sequence.go 81.83% <100%> (ø)
idm/idm.go 76.31% <100%> (ø)
drivers/overlay/ovmanager/ovmanager.go 52.34% <100%> (ø)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 7447e54...a2bcac0. Read the comment docs.

@fcrisciani
Copy link

@mavenugo will give another pass within the eod

idm/idm.go Outdated
@@ -38,7 +38,7 @@ func (i *Idm) GetID() (uint64, error) {
if i.handle == nil {
return 0, errors.New("ID set is not initialized")
}
ordinal, err := i.handle.SetAny()
ordinal, err := i.handle.SetAny(false)

Choose a reason for hiding this comment

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

don't we need the same sequential allocation for the vxlan? else we are going to hit the vxlan interface file already exists correct?


// AllocSerialPrefix constant marks the reserved label space for libnetwork ipam
// allocation ordering.(serial/first available)
AllocSerialPrefix = Prefix + "ipam.serial"
Copy link

@fcrisciani fcrisciani Sep 29, 2017

Choose a reason for hiding this comment

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

don't we need a point in the middle?
com.docker.network . ipam.serial?

@GordonTheTurtle
Copy link

Please sign your commits following these rules:
https://github.com/moby/moby/blob/master/CONTRIBUTING.md#sign-your-work
The easiest way to do this is to amend the last commit:

$ git clone -b "ipam_alloc" git@github.com:abhi/libnetwork.git somewhere
$ cd somewhere
$ git rebase -i HEAD~842354211816
editor opens
change each 'pick' to 'edit'
save the file and quit
$ git commit --amend -s --no-edit
$ git rebase --continue # and repeat the amend for each commit
$ git push -f

Amending updates the existing PR. You DO NOT need to open a new one.

Signed-off-by: Abhinandan Prativadi <abhi@docker.com>
@@ -56,7 +56,7 @@ func (i *Idm) GetSpecificID(id uint64) error {
}

// GetIDInRange returns the first available id in the set within a [start,end] range

Choose a reason for hiding this comment

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

I don't think that this is anymore accurate, correct? (being a comment it's not critical, can be handled on top)


i.Release(52)
err = i.GetSpecificID(52)
if err != nil {

Choose a reason for hiding this comment

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

can you check that is also 52 the value?

@fcrisciani
Copy link

2 small comments, rest LGTM
@mavenugo PTAL

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

6 participants