()
| 536 | } |
| 537 | |
| 538 | func (m *memLS) consistent() error { |
| 539 | m.mu.Lock() |
| 540 | defer m.mu.Unlock() |
| 541 | |
| 542 | // If m.byName is non-empty, then it must contain an entry for the root "/", |
| 543 | // and its refCount should equal the number of locked nodes. |
| 544 | if len(m.byName) > 0 { |
| 545 | n := m.byName["/"] |
| 546 | if n == nil { |
| 547 | return fmt.Errorf(`non-empty m.byName does not contain the root "/"`) |
| 548 | } |
| 549 | if n.refCount != len(m.byToken) { |
| 550 | return fmt.Errorf("root node refCount=%d, differs from len(m.byToken)=%d", n.refCount, len(m.byToken)) |
| 551 | } |
| 552 | } |
| 553 | |
| 554 | for name, n := range m.byName { |
| 555 | // The map keys should be consistent with the node's copy of the key. |
| 556 | if n.details.Root != name { |
| 557 | return fmt.Errorf("node name %q != byName map key %q", n.details.Root, name) |
| 558 | } |
| 559 | |
| 560 | // A name must be clean, and start with a "/". |
| 561 | if len(name) == 0 || name[0] != '/' { |
| 562 | return fmt.Errorf(`node name %q does not start with "/"`, name) |
| 563 | } |
| 564 | if name != path.Clean(name) { |
| 565 | return fmt.Errorf(`node name %q is not clean`, name) |
| 566 | } |
| 567 | |
| 568 | // A node's refCount should be positive. |
| 569 | if n.refCount <= 0 { |
| 570 | return fmt.Errorf("non-positive refCount for node at name %q", name) |
| 571 | } |
| 572 | |
| 573 | // A node's refCount should be the number of self-or-descendents that |
| 574 | // are locked (i.e. have a non-empty token). |
| 575 | var list []string |
| 576 | for name0, n0 := range m.byName { |
| 577 | // All of lockTestNames' name fragments are one byte long: '_', 'i' or 'z', |
| 578 | // so strings.HasPrefix is equivalent to self-or-descendent name match. |
| 579 | // We don't have to worry about "/foo/bar" being a false positive match |
| 580 | // for "/foo/b". |
| 581 | if strings.HasPrefix(name0, name) && n0.token != "" { |
| 582 | list = append(list, name0) |
| 583 | } |
| 584 | } |
| 585 | if n.refCount != len(list) { |
| 586 | sort.Strings(list) |
| 587 | return fmt.Errorf("node at name %q has refCount %d but locked self-or-descendents are %q (len=%d)", |
| 588 | name, n.refCount, list, len(list)) |
| 589 | } |
| 590 | |
| 591 | // A node n is in m.byToken if it has a non-empty token. |
| 592 | if n.token != "" { |
| 593 | if _, ok := m.byToken[n.token]; !ok { |
| 594 | return fmt.Errorf("node at name %q has token %q but not in m.byToken", name, n.token) |
| 595 | } |
no test coverage detected