Subject: [netmod] unique-stmt

From: Andy Bierman <[email-masked]>
Date: Mon, 09 Feb 2009 17:39:39 -0800

Hi,

I do not understand how the text in 7.8.3 is supposed
to be implemented for complex examples, where 2 or
more leaf targets in the unique-stmt are nested inside
other lists:

    list foo {
      key a;
      unique "b bb/bbb cc/ccc";

      leaf a { type string; }

      leaf b { type string; }

      list bb {
         key bbkey;
         leaf bbkey { type string; }
         leaf bbb { type string; }
      }

      list cc {
         key cckey;
         leaf cckey { type string; }
         leaf ccc { type string; }
      }
    }

I do not understand which instances get compared in
each 3-tuple, since 'bb' and 'cc' are different lists
and have nothing to do with each other.

The trivial example in the draft makes sense to me,
because all the nodes in the unique-stmt are siblings
of each other.  I prefer that a CLR be added that
unique-stmt tuple members MUST be siblings
(even if they are nested in many lists).

If not, then lots more text is needed explaining
the expected behavior for the unique-stmt.

Andy

---

From: Andy Bierman <[email-masked]>
Date: Wed, 11 Feb 2009 10:09:02 -0800

> Hi,

I will try an example, because the unique-stmt is
powerful (IMO too powerful) and it needs to be
interoperable as well.

In this example the nodes tested for uniqueness are
optional, not instance-related, and the numbers of
each are all different.

XML:

   <foo>
     <a>a1</a>
     <b>red</b>
     <bb>
       <bbkey>item1</bbkey>
       <bbb>up</bbb>
     </bb>
     <bb>
       <bbkey>item2</bbkey>
     </bb>
     <bb>
       <bbkey>item3</bbkey>
       <bbb>down</bbb>
     </bb>
     <cc>
       <cckey>row1</cckey>
       <ccc>left</ccc>
     </cc>
     <cc>
       <cckey>row2</cckey>
       <ccc>right</ccc>
     </cc>
     <cc>
       <cckey>row3</cckey>
       <ccc>center</ccc>
     </cc>
     <cc>
       <cckey>row4</cckey>
       <ccc>center</ccc>
     </cc>
   </foo>

YANG:

Nodes:

   (1) /foo[a='a1']/b = 'red'
   (2) /foo[a='a1']/bb[bbkey='item1']/bbb = 'up'
   (3) /foo[a='a1']/bb[bbkey='item3']/bbb = 'down'
   (4) /foo[a='a1']/cc[cckey='row1']/ccc = 'left'
   (5) /foo[a='a1']/cc[cckey='row1']/ccc = 'right'
   (6) /foo[a='a1']/cc[cckey='row1']/ccc = 'center'
   (7) /foo[a='a1']/cc[cckey='row1']/ccc = 'center'

Tuples:

   T1 = [1, 2, 4] = (red, up, left)
   T2 = [1, 2, 5] = (red, up, right)
   T3 = [1, 2, 6] = (red, up, center)
   T4 = [1, 2, 7] = (red, up, center)
   T5 = [1, 3, 4] = (red, down, left)
   T6 = [1, 3, 5] = (red, down, right)
   T7 = [1, 3, 6] = (red, down, center)
   T8 = [1, 3, 7] = (red, down, center)

Result:

   data-not-unique error generated for T3 = T4
   data-not-unique error generated for T7 = T8

Is this right?
The agent should internally construct these tuples,
and compare each one to every other tuple?

I do not see how the 'b' and 'bbb' nodes affect the result
in this example.  The unique-stmt design seems to assume
some instance relationship between the nodes, without
specifying it.

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 11 Feb 2009 21:54:56 +0100 (CET)

Andy Bierman <[email-masked]> wrote:
> powerful (IMO too powerful)

Yes I agree.   I think we need to restrict it the same way as XSD
does for xs:unique. 

For each list entry instance, exactly one tuple is constructed, and
this tuple must be unique across all list entry instances.  The tuple
consists of as many elements as there are schema node identifiers in
the unique expression.  Each such schema node identifier MUST select
zero (*) or one leaf (**).  If one of the schema node identifiers
selects zero leafs, then the entire tuple is ignored.

(*) this can happen if the leaf is optional, and not set for a
particular instance.

(**) this corresponds to the XSD restriction in xs:unique (each
xs:field must return a nodeset with at most element)

>    unique "b bb/bbb cc/ccc";

each tuple would have 3 elements.  However, since both bb and cc are
lists, 'bb/bbb' will (may) select more than one leaf, and this would
an invalid constraint.

We could simply state that each node in the schema node identifier
MUST be a 'container' or a 'leaf'.  I.e. it would not be possible to
go into sublists in a unique expression.

/martin

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 11 Feb 2009 21:57:00 +0100 (CET)

Martin Bjorklund <[email-masked]> wrote:
> MUST be a 'container' or a 'leaf'.

Or 'choice' or 'case'.  This would still select at most one leaf.

/martin

---

From: Andy Bierman <[email-masked]>
Date: Wed, 11 Feb 2009 13:30:00 -0800

> Or 'choice' or 'case'.  This would still select at most one leaf.

This solution is fine with me.

Does this work for the use case you brought up awhile back,
about the unique address within the interface list?

This example is not a problem, because there is only 1 node
in the unique-stmt:

   list interface {
      key ...;

      unique "subsys/address";

      list subsys {

         key ...;

         // why not just put 'unique address;' here?

         leaf address { type inet:inet-address; }
      }
   }

Can you show an example with multiple nodes in the unique-stmt,
with targets at different nest levels?

   list interface {
      key ...;

      unique "subsys/address port";

      list subsys {

         key ...;

         leaf address { type inet:inet-address; }
      }

      leaf port { type uint8; }
   }

Is this valid?

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 11 Feb 2009 22:40:01 +0100 (CET)

>          leaf address { type inet:inet-address; }

Maybe the example is not perfect, since it can be ok to have the same
address on different interfaces.  But no, this use case would not be
covered.

> with targets at different nest levels?

Targets at different nested list levels would not be allowed.  Nesting
in containers would be ok:

   list server {
       key ...;
       unique "address/ip address/port";
 
       container address {
           leaf ip { ... }
           leaf port { ... }
       }
   }

>       leaf port { type uint8; }

No it would not be valid.

/martin

---

From: Andy Bierman <[email-masked]>
Date: Wed, 11 Feb 2009 14:04:58 -0800

> address on different interfaces.  But no, this use case would not be

OK

>        unique "address/ip address/port";

Do you mean the all nodes specified in the unique-stmt
must be siblings?  Same level can mean different parents.

> No it would not be valid.

OK.
So even if there were no restrictions, my previous example
would have stopped cold because there was only one '/foo'
list entry.  Only 0 or 1 tuple can come out of each list entry.
The unique-stmt is always applied across all entries, never
within a single entry.

Andy

---

From: Martin Bjorklund <[email-masked]>
Date: Wed, 11 Feb 2009 23:20:20 +0100 (CET)

> must be siblings?  Same level can mean different parents.

No, this would be ok as well:

   list foo {
       key ...;
       unique "a/b c";
 
       container a {
           leaf b { ... }
       }
       leaf c { ... }
   }

The point is that each "schema node identifier" part of the unique
expression (i.e. "a/b" and "c") selects at most one node.

/martin