river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject ServiceDiscoveryManager lookp specification
Date Tue, 07 May 2013 10:17:18 GMT
This test smells broken?

I modified the output to read in milliseconds.

Relevant ServiceDiscoveryManager method under test:

public ServiceItem[] lookup(ServiceTemplate tmpl,
                                 int minMatches,
                                 int maxMatches,
                                 ServiceItemFilter filter,
                                 long waitDur)
                                  throws InterruptedException,
                                         RemoteException {...}



To summarise what's happens (occassionally):

CASE 1:

    * ServiceDiscoveryManager.lookup  is called and blocks waiting until
      it receives the minimum number of ServiceItems.
    * If the required number of ServiceItem's are discovered late, the
      waitDur limit will be approached when lookup returns.
          o The resolution of the test is to the nearest second, not
            millisecond.


    Firstly I don't believe this is the intent of the Jini Standard
    SD4.1.3 The blocking feature of lookup, which states:

        As noted above, each category contains a version of |lookup|
        that provides a feature in which the entity can request that if
        the number of service references found throughout the available
        lookup services does not fall into a desired range, the method
        will wait a finite period of time until either an acceptable
        minimum number of service references are discovered or the
        specified time period has passed.


    In this case the specified time period hasn't quite passed, however
    an acceptable minimum number of service references are returned and
    the test fails.  This failure is rare.


CASE 2:

              * 3. while lookup() is blocking, if enough new services are
              *    registered so that the acceptable minimum is achieved,
              *    lookup() will return immediately; that is, even if there
              *    is more time left on the wait period, lookup() will not
              *    wait for more services beyond the minimum.
              *
              *    For example, if 3 services are initially registered and
              *    lookup is called with min = 4 and max = 7, then lookup()
              *    will find the 3 services and then wait for more 
services to
              *    be registered. Suppose that while lookup() is blocking
              *    another 5 services are registered, bringing the total 
number
              *    of services to 8. In this case, lookup() will stopping
              *    waiting and return 4 services (the minimum), not the
              *    maximum 7.

While the test performs this check, it isn't implemented in 
ServiceDiscoveryManager, instead it's left up to chance that the lookup 
method, waiting on an object monitor will obtain the monitor as soon as 
it's notified.  However if multiple threads contend for the lock, it's 
very unlikely the thread scheduler will give the object monitor to the 
waiting thread, instead the most recently blocking thread is likely to 
get the monitor.

This requirment in the test appears to be additional to the 
specification and would require ServiceDiscoveryManager be modified, to 
use some kind of fair Lock scheme.  However doing this would 
unnecessarily complicate ServiceDiscoveryManager, instead it would be 
simpler to return the number of ServiceItem's found up to the maxMatches 
at the time the lock is obtained.

CASE 1 test results:

Running com/sun/jini/test/spec/servicediscovery/lookup/LookupMinLessMax.td
Time is Mon May 06 22:17:31 EST 2013
Starting test in separate process with command:
'C:\Program Files\Java\jdk1.6.0_26\jre\bin\java' 
-Djava.security.manager=org.apache.river.api.security.CombinerSecurityManager 
-Djava.security.policy=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/harness/policy/defaulttest.policy

-Djava.rmi.server.codebase=http://medusa:9082/qa1-servicediscovery-dl.jar -cp 
C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jiniharness.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jinitests.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\jsk-platform.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\jsk-lib.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\high-scale-lib.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\custard-apple-1.0.3.jar

-ea -esa -client '-Djava.ext.dirs=C:\Program 
Files\Java\jdk1.6.0_26\jre\lib\ext;C:\windows\Sun\Java\lib\ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib-ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib-ext'

-Dcom.sun.jini.jsk.port=9080 -Dcom.sun.jini.qa.port=9081 
-Dcom.sun.jini.jsk.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy 
-Dcom.sun.jini.qa.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa

-Dcom.sun.jini.qa.harness.harnessJar=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jiniharness.jar

-Dcom.sun.jini.qa.harness.testJar=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jinitests.jar

-Dcom.sun.jini.qa.harness.runjiniserver=true 
-Dcom.sun.jini.qa.harness.runkitserver=true 
-Djava.security.properties=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/harness/trust/dynamic-policy.properties

-Dcom.sun.jini.qa.harness.testhosts= 
-Djava.util.logging.config.file=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\src\com\sun\jini\test\resources\qa1.logging

-Dcom.sun.jini.test.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa

-Dcom.sun.jini.test.port=9082 
-Dcom.sun.jini.qa.harness.policies=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/src/com/sun/jini/test/resources/jinitest.policy

'-Djava.ext.dirs=C:\Program 
Files\Java\jdk1.6.0_26\jre\lib\ext;C:\windows\Sun\Java\lib\ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib-ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib-ext'

com.sun.jini.qa.harness.MasterTest 
com/sun/jini/test/spec/servicediscovery/lookup/LookupMinLessMax.td
com.sun.jini.qa.harness.TestException:  -- blocked longer than expected 
-- requested block = 60000 millisecond(s), actual block = 59999 
millisecond(s)
     at 
com.sun.jini.test.spec.servicediscovery.lookup.LookupMinEqualsMax.verifyBlocking(LookupMinEqualsMax.java:288)
     at 
com.sun.jini.test.spec.servicediscovery.lookup.LookupMinEqualsMax.applyTestDef(LookupMinEqualsMax.java:120)
     at 
com.sun.jini.test.spec.servicediscovery.AbstractBaseTest.run(AbstractBaseTest.java:549)
     at com.sun.jini.qa.harness.MasterTest.doTest(MasterTest.java:256)
     at com.sun.jini.qa.harness.MasterTest.main(MasterTest.java:144)

TIME: 10:20:02 PM

Test process was destroyed and returned code 1
com/sun/jini/test/spec/servicediscovery/lookup/LookupMinLessMax.td
Test Failed: Test Failed: com.sun.jini.qa.harness.TestException:  -- 
blocked longer than expected -- requested block = 60000 millisecond(s), 
actual block = 59999 millisecond(s)

Running com/sun/jini/test/spec/servicediscovery/lookup/LookupMinLessMax.td
Running com/sun/jini/test/spec/servicediscovery/lookup/LookupMinLessMax.td
Time is Tue May 07 10:40:30 EST 2013
Time is Tue May 07 10:40:30 EST 2013
Starting test in separate process with command:
Starting test in separate process with command:
'C:\Program Files\Java\jdk1.6.0_26\jre\bin\java' 
-Djava.security.manager=org.apache.river.api.security.CombinerSecurityManager 
-Djava.security.policy=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/harness/policy/defaulttest.policy

-Djava.rmi.server.codebase=http://medusa:9082/qa1-servicediscovery-dl.jar -cp 
C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jiniharness.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jinitests.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\jsk-platform.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\jsk-lib.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\high-scale-lib.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\custard-apple-1.0.3.jar

-ea -esa -client '-Djava.ext.dirs=C:\Program 
Files\Java\jdk1.6.0_26\jre\lib\ext;C:\windows\Sun\Java\lib\ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib-ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib-ext'

-Dcom.sun.jini.jsk.port=9080 -Dcom.sun.jini.qa.port=9081 
-Dcom.sun.jini.jsk.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy 
-Dcom.sun.jini.qa.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa

-Dcom.sun.jini.qa.harness.harnessJar=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jiniharness.jar

-Dcom.sun.jini.qa.harness.testJar=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jinitests.jar

-Dcom.sun.jini.qa.harness.runjiniserver=true 
-Dcom.sun.jini.qa.harness.runkitserver=true 
-Djava.security.properties=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/harness/trust/dynamic-policy.properties

-Dcom.sun.jini.qa.harness.testhosts= 
-Djava.util.logging.config.file=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\src\com\sun\jini\test\resources\qa1.logging

-Dcom.sun.jini.test.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa

-Dcom.sun.jini.test.port=9082 
-Dcom.sun.jini.qa.harness.policies=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/src/com/sun/jini/test/resources/jinitest.policy

'-Djava.ext.dirs=C:\Program 
Files\Java\jdk1.6.0_26\jre\lib\ext;C:\windows\Sun\Java\lib\ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib-ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib-ext'

com.sun.jini.qa.harness.MasterTest 
com/sun/jini/test/spec/servicediscovery/lookup/LookupMinLessMax.td
'C:\Program Files\Java\jdk1.6.0_26\jre\bin\java' 
-Djava.security.manager=org.apache.river.api.security.CombinerSecurityManager 
-Djava.security.policy=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/harness/policy/defaulttest.policy

-Djava.rmi.server.codebase=http://medusa:9082/qa1-servicediscovery-dl.jar -cp 
C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jiniharness.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jinitests.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\jsk-platform.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\jsk-lib.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\high-scale-lib.jar;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib\custard-apple-1.0.3.jar

-ea -esa -client '-Djava.ext.dirs=C:\Program 
Files\Java\jdk1.6.0_26\jre\lib\ext;C:\windows\Sun\Java\lib\ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib-ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib-ext'

-Dcom.sun.jini.jsk.port=9080 -Dcom.sun.jini.qa.port=9081 
-Dcom.sun.jini.jsk.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy 
-Dcom.sun.jini.qa.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa

-Dcom.sun.jini.qa.harness.harnessJar=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jiniharness.jar

-Dcom.sun.jini.qa.harness.testJar=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib\jinitests.jar

-Dcom.sun.jini.qa.harness.runjiniserver=true 
-Dcom.sun.jini.qa.harness.runkitserver=true 
-Djava.security.properties=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/harness/trust/dynamic-policy.properties

-Dcom.sun.jini.qa.harness.testhosts= 
-Djava.util.logging.config.file=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\src\com\sun\jini\test\resources\qa1.logging

-Dcom.sun.jini.test.home=C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa

-Dcom.sun.jini.test.port=9082 
-Dcom.sun.jini.qa.harness.policies=file:/C:/Users/peter/Documents/NetBeansProjects/peterConcurrentPolicy/qa/src/com/sun/jini/test/resources/jinitest.policy

'-Djava.ext.dirs=C:\Program 
Files\Java\jdk1.6.0_26\jre\lib\ext;C:\windows\Sun\Java\lib\ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\qa\lib-ext;C:\Users\peter\Documents\NetBeansProjects\peterConcurrentPolicy\lib-ext'

com.sun.jini.qa.harness.MasterTest 
com/sun/jini/test/spec/servicediscovery/lookup/LookupMinLessMax.td
com.sun.jini.qa.harness.TestException:  -- blocked longer than expected 
-- requested block = 60000 millisecond(s), actual block = 59997 
millisecond(s) wait error = 0
com.sun.jini.qa.harness.TestException:  -- blocked longer than expected 
-- requested block = 60000 millisecond(s), actual block = 59997 
millisecond(s) wait error = 0
     at 
com.sun.jini.test.spec.servicediscovery.lookup.LookupMinEqualsMax.verifyBlocking(LookupMinEqualsMax.java:288)
     at 
com.sun.jini.test.spec.servicediscovery.lookup.LookupMinEqualsMax.applyTestDef(LookupMinEqualsMax.java:120)
     at 
com.sun.jini.test.spec.servicediscovery.AbstractBaseTest.run(AbstractBaseTest.java:549)
     at com.sun.jini.qa.harness.MasterTest.doTest(MasterTest.java:256)
     at com.sun.jini.qa.harness.MasterTest.main(MasterTest.java:144)




Relevant Section of Jini Specification:


          SD.4.1.3 The |lookup| Method

The |lookup| method queries each available lookup service in the managed 
set for service reference(s) that match criteria defined by the entity 
that invokes this method. Entities typically employ this method when 
they need infrequent access to services and when the cost of making 
remote queries is outweighed by the overhead of maintaining a local 
cache (for example, because of resource limitations).

The |lookup| method has four versions, each version falling into one of 
two categories: those versions of this method that return a single 
instance of |ServiceItem| and those versions that return a set of 
service references as an array of |ServiceItem| objects.

Two arguments are common to all versions of this method: an instance of 
|ServiceTemplate| and an instance of |ServiceItemFilter|.

Within each category, the versions of |lookup| differ only in whether or 
not a particular version provides what is referred to as a "wait" (or 
blocking) feature. That is, each category contains both a non-blocking 
version of |lookup| which returns immediately when unable to find the 
desired service, and a blocking version which returns only after waiting 
a specified amount of time for the desired service to be discovered. The 
particular version of |lookup| that an entity employs is typically 
determined by the entity's intended usage pattern.

The descriptions that follow refer to all versions of the |lookup| 
method, except where explicitly noted.

The |tmpl| argument and the |filter| argument both have semantics 
identical to that defined for these arguments in the description of the 
|createLookupCache| method above. In particular,

    * A |null| reference value for the |tmpl| parameter is treated as
      the equivalent of a "wildcarded" |ServiceTemplate|.

    * If |null| is the value for the |filter| parameter, only template
      matching will be employed to find the desired services.

    * The effects of modifying the contents of the |tmpl| parameter
      while the invocation is in progress are unpredictable and undefined.

If no service can be found that matches the desired criteria, then the 
versions of |lookup| from the first category--those that return a single 
instance of |ServiceItem|--will return |null|, whereas the versions from 
the second category--those that return an array of |ServiceItem| 
instances--will return an empty array.

The versions of |lookup| from the first category can be used in a 
fashion similar to the first form of the |lookup| method defined in the 
|ServiceRegistrar| interface described in the /Jini Lookup Service 
Specification/. That is, an entity would typically invoke one of these 
versions of |lookup| when it wishes to find a /single/ service reference 
and the particular lookup service with which that service reference is 
registered is unimportant to the entity.

Each version of |lookup| defined in the |ServiceDiscoveryManager| 
differs with the corresponding version of |lookup| in |ServiceRegistrar| 
in the following ways:

    * The versions of |lookup| defined in the |ServiceDiscoveryManager|
      query /multiple/ lookup services (the order in which the lookup
      services are queried is dependent on the implementation).

    * The versions of |lookup| defined in the |ServiceDiscoveryManager|
      can apply additional selection criteria, in the form of a filter
      object, when deciding whether a service reference found through
      standard template matching should be returned to the entity.

The versions of |lookup| that return an array of |ServiceItem| objects 
can be used in a fashion similar to the second form of |lookup| defined 
in the |ServiceRegistrar| interface. That is, an entity would typically 
invoke these versions of |lookup| when it wishes to find /multiple/ 
service references that satisfy the input criteria. Each of the versions 
of |lookup| that return an array of |ServiceItem| objects takes as one 
of its arguments an |int| parameter, |maxMatches|, that represents the 
maximum number of matches that should be returned. The array returned by 
these methods will contain no more than |maxMatches| service references, 
although it may contain fewer than that number.

As with the versions of |lookup| that return a single instance of 
|ServiceItem|, multiple queries and filtering are also notable 
differences between the second-category versions of this method and 
their counterpart in |ServiceRegistrar|.

For each version of |lookup|, whenever a lookup service query returns a 
|null| service reference, the filter is bypassed, and the service 
reference is excluded from the return object. On the other hand, if the 
query returns a non-|null| service reference in which the associated 
array of attribute contains one or more |null| elements, the filter is 
still applied and the service reference is included in the return object.

Each version of |lookup| may be confronted with duplicate references 
during a search for a service of interest. This is because the same 
service may register with more than one lookup service in the managed 
set. As with the cache, when a set of service references is returned by 
|lookup|, each service reference in the return set will be unique with 
respect to all other service references in the set, as determined by the 
|equals| method provided by each reference.

If it is determined that a lookup service is unavailable (due to an 
exception or some other non-fatal error) while interacting with a lookup 
service from the managed set, all versions of |lookup| will invoke the 
|discard| method on the instance of |DiscoveryManagement| being employed 
by the |ServiceDiscoveryManager|. Doing so will result in the 
unavailable lookup service being discarded and made eligible for 
rediscovery.

Recall that the propagation of modifications to a service's attributes 
across a set of lookup services typically occurs asynchronously. It is 
for this reason that while invoking |lookup| to find a set of matching 
services, it is possible that the set returned may contain multiple 
references having the same service ID with different attributes. Note 
that although this sort of inconsistent state can also occur if the 
entity employs a cache, the cache will eventually reflect the correct 
state.

The Blocking Feature of |lookup|

As noted above, each category contains a version of |lookup| that 
provides a feature in which the entity can request that if the number of 
service references found throughout the available lookup services does 
not fall into a desired range, the method will wait a finite period of 
time until either an acceptable minimum number of service references are 
discovered or the specified time period has passed.

The versions of |lookup| providing this blocking feature each takes as 
one of its parameters a value of type long that represents the number of 
milliseconds to wait for the service to be discovered. In addition to 
|RemoteException| (described previously for these methods), each of 
these versions of |lookup| may throw an |InterruptedException|.

One of these blocking versions of |lookup| implicitly uses a value of 
one for both the acceptable minimum and the allowable maximum number of 
service references to discover. The other blocking version requires that 
the entity specify the range through the |minMatches| and |maxMatches| 
parameters, respectively.

Prior to blocking, each of these versions of |lookup| first queries each 
available lookup service in an attempt to retrieve a satisfactory number 
of matching services. Whether or not the method actually blocks is 
dependent on how many matching service references are found during the 
query process. Blocking occurs only if after querying /all/ of the 
available lookup services, the number of matching services found is less 
than the acceptable minimum. If the waiting period (measured from when 
blocking first begins) passes before that minimum number of service 
references is found, the method will return the service references that 
have been discovered up to that point. If the waiting period passes and 
no services have been found, |null| or an empty array (depending on the 
version of |lookup|) will be returned.

If, after querying all of the available lookup services, the number of 
services found to satisfy the desired criteria is greater than or equal 
to the specified minimum but less than the specified maximum, the method 
will return the currently discovered service references without 
blocking. If the initial query process produces the desired maximum 
number of service references, the method will return the results 
immediately.

The blocking versions of |lookup| are quite useful to entities that 
cannot proceed until such a service of interest is found. If a 
non-positive value is input to the |waitDur| argument, then the method 
will not wait. It will simply query the available lookup services and 
employ the return semantics described above.

The values of the |minMatches| and |maxMatches| arguments must both be 
positive, and |maxMatches| must be greater than or equal to 
|minMatches|; otherwise, an |IllegalArgumentException| will be thrown.

The blocking versions of |lookup| make a concurrency guarantee with 
respect to the discovery of new lookup services during the wait period. 
That is, while waiting for the desired service reference(s) to be 
discovered, if one or more of the targeted--but previously 
unavailable--lookup services is discovered and added to the managed set, 
those new lookup services will also be queried for the service(s) of 
interest.

In addition, the blocking versions of |lookup| throw 
|InterruptedException|. When an entity invokes either version with valid 
parameters, the entity may decide during the wait period that it no 
longer wishes to wait the entire period for the method to return. Thus, 
while the method is blocking on the discovery of matching service(s), it 
may be interrupted by invoking the |interrupt| method from the |Thread| 
class. The intent of this mechanism is to allow the entity to interrupt 
a blocking |lookup| in the same way it would a sleeping thread.



Mime
View raw message