Fixes #5166
Current graph.restore is essentially O(n^2 log n) due to how
suffixarray creation works.
Rather than create/append/create new this supports creation from a seed
array of ids.
Functional testing shows this eliminates the hang on Creating image
graph reported on list.
Docker-DCO-1.1-Signed-off-by: Paul Nasrat <pnasrat@gmail.com> (github: pnasrat)
| ... | ... |
@@ -40,7 +40,7 @@ func NewGraph(root string, driver graphdriver.Driver) (*Graph, error) {
|
| 40 | 40 |
|
| 41 | 41 |
graph := &Graph{
|
| 42 | 42 |
Root: abspath, |
| 43 |
- idIndex: utils.NewTruncIndex(), |
|
| 43 |
+ idIndex: utils.NewTruncIndex([]string{}),
|
|
| 44 | 44 |
driver: driver, |
| 45 | 45 |
} |
| 46 | 46 |
if err := graph.restore(); err != nil {
|
| ... | ... |
@@ -54,12 +54,14 @@ func (graph *Graph) restore() error {
|
| 54 | 54 |
if err != nil {
|
| 55 | 55 |
return err |
| 56 | 56 |
} |
| 57 |
+ var ids = []string{}
|
|
| 57 | 58 |
for _, v := range dir {
|
| 58 | 59 |
id := v.Name() |
| 59 | 60 |
if graph.driver.Exists(id) {
|
| 60 |
- graph.idIndex.Add(id) |
|
| 61 |
+ ids = append(ids, id) |
|
| 61 | 62 |
} |
| 62 | 63 |
} |
| 64 |
+ graph.idIndex = utils.NewTruncIndex(ids) |
|
| 63 | 65 |
utils.Debugf("Restored %d elements", len(dir))
|
| 64 | 66 |
return nil |
| 65 | 67 |
} |
| ... | ... |
@@ -779,7 +779,7 @@ func NewRuntimeFromDirectory(config *daemonconfig.Config, eng *engine.Engine) (* |
| 779 | 779 |
containers: list.New(), |
| 780 | 780 |
graph: g, |
| 781 | 781 |
repositories: repositories, |
| 782 |
- idIndex: utils.NewTruncIndex(), |
|
| 782 |
+ idIndex: utils.NewTruncIndex([]string{}),
|
|
| 783 | 783 |
sysInfo: sysInfo, |
| 784 | 784 |
volumes: volumes, |
| 785 | 785 |
config: config, |
| ... | ... |
@@ -426,12 +426,17 @@ type TruncIndex struct {
|
| 426 | 426 |
bytes []byte |
| 427 | 427 |
} |
| 428 | 428 |
|
| 429 |
-func NewTruncIndex() *TruncIndex {
|
|
| 430 |
- return &TruncIndex{
|
|
| 431 |
- index: suffixarray.New([]byte{' '}),
|
|
| 429 |
+func NewTruncIndex(ids []string) (idx *TruncIndex) {
|
|
| 430 |
+ idx = &TruncIndex{
|
|
| 432 | 431 |
ids: make(map[string]bool), |
| 433 | 432 |
bytes: []byte{' '},
|
| 434 | 433 |
} |
| 434 |
+ for _, id := range ids {
|
|
| 435 |
+ idx.ids[id] = true |
|
| 436 |
+ idx.bytes = append(idx.bytes, []byte(id+" ")...) |
|
| 437 |
+ } |
|
| 438 |
+ idx.index = suffixarray.New(idx.bytes) |
|
| 439 |
+ return |
|
| 435 | 440 |
} |
| 436 | 441 |
|
| 437 | 442 |
func (idx *TruncIndex) Add(id string) error {
|
| ... | ... |
@@ -138,7 +138,8 @@ func TestRaceWriteBroadcaster(t *testing.T) {
|
| 138 | 138 |
|
| 139 | 139 |
// Test the behavior of TruncIndex, an index for querying IDs from a non-conflicting prefix. |
| 140 | 140 |
func TestTruncIndex(t *testing.T) {
|
| 141 |
- index := NewTruncIndex() |
|
| 141 |
+ ids := []string{}
|
|
| 142 |
+ index := NewTruncIndex(ids) |
|
| 142 | 143 |
// Get on an empty index |
| 143 | 144 |
if _, err := index.Get("foobar"); err == nil {
|
| 144 | 145 |
t.Fatal("Get on an empty index should return an error")
|