You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@jena.apache.org by "Andy Seaborne (JIRA)" <ji...@apache.org> on 2013/08/23 16:36:51 UTC

[jira] [Comment Edited] (JENA-522) DatasetGraphWithLock claims to support multiple readers but appears not to

    [ https://issues.apache.org/jira/browse/JENA-522?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13748578#comment-13748578 ] 

Andy Seaborne edited comment on JENA-522 at 8/23/13 2:35 PM:
-------------------------------------------------------------

I agree there is some some of problem but I think it's something different.

The check DatasetGraphWithLock.checkActive() is wrong.  It's not thread sensitive.

An example: the code at the bottom of this comment should prints, pause, then prints again.   I see partial overlaps as would be expected by multiple threads in the read region but not all threads print anything.  They have died at {{dsg.begin}}.  If you comment out in DatasetGraphWithLock as below ...

{noformat}
    @Override
    protected void checkActive()
    {
//        if ( ! isInTransaction() )
//            throw new JenaLockException("Not in a locked region") ;
    }

    @Override
    protected void checkNotActive()
    {
//        if ( isInTransaction() )
//            throw new JenaLockException("Currently in a locked region") ;
    }
{noformat}

... then I get the expected overlaps fro the code below.

{{isInTransaction}} is being set wrongly - it needs to be a thread local (like it is in DatasetGraphTransaction)

{noformat}
public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool() ;

        final DatasetGraphWithLock dsg = new DatasetGraphWithLock(DatasetGraphFactory.createMem());

        Callable<Boolean> callable = new Callable<Boolean>() {

                @Override
                public Boolean call() throws Exception {
                    int x = counter.incrementAndGet() ;

                    // Get a read lock
                    try { dsg.begin(ReadWrite.READ); }
                    catch (RuntimeException ex) {
                        System.err.println("Exception in .begin ("+x+")") ;
                        ex.printStackTrace(System.err) ;
                        return false ;
                    }

                    // Hold the lock for a short time
                    try {
                        System.err.println("Task "+x+" start") ;
                        Thread.sleep(500);
                        System.err.println("Task "+x+" finish") ;
                   } catch (InterruptedException e) {
                       System.err.println("InterruptedException") ;
                       e.printStackTrace(System.err); 
                   }

                    exitCounter.incrementAndGet() ;
                    try { dsg.commit(); }
                    catch (RuntimeException ex) {
                        System.err.println("Exception in .commit ("+x+")") ;
                        ex.printStackTrace(System.err) ;
                        return false ;
                    }
                    return true;
                }

            };

            int N = 10 ;
            
            for (int i = 0; i < N; i++) {
                executor.submit(callable) ;
            }
            
            for ( ;; ) {
                if ( exitCounter.intValue() != N )
                    Lib.sleep(500);
            }
    }
{noformat}
                
      was (Author: andy.seaborne):
    I agree there is some some of problem but I think it's something different.

The check DatasetGraphWithLock.checkActive() is wrong.  It's not thread sensitive.

An example: it prints and pauses, then prints again.   I see partial overlaps as would be expected by multiple threads in the read region but not all threads print anything.  They have died at {{dsg.begin}}.  If you comment out in DatasetGraphWithLock as below ...

{noformat}
    @Override
    protected void checkActive()
    {
//        if ( ! isInTransaction() )
//            throw new JenaLockException("Not in a locked region") ;
    }

    @Override
    protected void checkNotActive()
    {
//        if ( isInTransaction() )
//            throw new JenaLockException("Currently in a locked region") ;
    }
{noformat}

... then I get the expected overlaps fro the code below.

{{isInTransaction}} is being set wrongly - it needs to be a thread local (like it is in DatasetGraphTransaction)

{noformat}
public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool() ;

        final DatasetGraphWithLock dsg = new DatasetGraphWithLock(DatasetGraphFactory.createMem());

        Callable<Boolean> callable = new Callable<Boolean>() {

                @Override
                public Boolean call() throws Exception {
                    int x = counter.incrementAndGet() ;

                    // Get a read lock
                    try { dsg.begin(ReadWrite.READ); }
                    catch (RuntimeException ex) {
                        System.err.println("Exception in .begin ("+x+")") ;
                        ex.printStackTrace(System.err) ;
                        return false ;
                    }

                    // Hold the lock for a short time
                    try {
                        System.err.println("Task "+x+" start") ;
                        Thread.sleep(500);
                        System.err.println("Task "+x+" finish") ;
                   } catch (InterruptedException e) {
                       System.err.println("InterruptedException") ;
                       e.printStackTrace(System.err); 
                   }

                    exitCounter.incrementAndGet() ;
                    try { dsg.commit(); }
                    catch (RuntimeException ex) {
                        System.err.println("Exception in .commit ("+x+")") ;
                        ex.printStackTrace(System.err) ;
                        return false ;
                    }
                    return true;
                }

            };

            int N = 10 ;
            
            for (int i = 0; i < N; i++) {
                executor.submit(callable) ;
            }
            
            for ( ;; ) {
                if ( exitCounter.intValue() != N )
                    Lib.sleep(500);
            }
    }
{noformat}
                  
> DatasetGraphWithLock claims to support multiple readers but appears not to
> --------------------------------------------------------------------------
>
>                 Key: JENA-522
>                 URL: https://issues.apache.org/jira/browse/JENA-522
>             Project: Apache Jena
>          Issue Type: Bug
>          Components: ARQ
>    Affects Versions: Jena 2.10.2
>            Reporter: Rob Vesse
>              Labels: concurrency, lock, multi-threading
>
> This bug originates out of a StackOverflow question pertaining to jena-text
> http://stackoverflow.com/q/18385738/107591
> However upon investigation the culprit appears to be {{DatasetGraphWithLock}}, reproducing my analysis from my SO answer here:
> {quote}
> The issue is that the dataset with inference implicitly uses ARQ's standard in-memory Dataset implementation and this does not support transactions.
> However text datasets which correspond to {{DatasetGraphText}} internally (and in your stack trace) requires the wrapped dataset to support transactions and where they do not wraps them with {{DatasetGraphWithLock}}. It is this that appears to be encountering the problem with the lock, the documentation states that this should support multiple readers but having followed the logic of the code I'm not sure that it actually allows this.
> {quote}
> I put together the following test case which illustrates the issue:
> {noformat}
>     @Test
>     public synchronized void dsg_with_lock_concurrency_02() throws InterruptedException, ExecutionException, TimeoutException {
>         ExecutorService executor = Executors.newCachedThreadPool();
>         try {
>             final DatasetGraphWithLock dsg = new DatasetGraphWithLock(DatasetGraphFactory.createMem());
>             Callable<Boolean> callable = new Callable<Boolean>() {
>                 @Override
>                 public Boolean call() throws Exception {
>                     // Get a read lock
>                     dsg.begin(ReadWrite.READ);
>                     // Hold the lock for a short time
>                     try {
>                         Thread.sleep(500);
>                     } catch (InterruptedException e) {
>                         // Ignore error
>                     }
>                     // Release the lock
>                     dsg.commit();
>                     return true;
>                 }
>             };
>             // Run the callable a bunch of times
>             List<Future<Boolean>> futures = new ArrayList<Future<Boolean>>();
>             for (int i = 0; i < 100; i++) {
>                 futures.add(executor.submit(callable));
>             }
>             // Check all the futures come back OK
>             for (Future<Boolean> f : futures) {
>                 Assert.assertTrue(f.get(3, TimeUnit.SECONDS));
>             }
>         } finally {
>             executor.shutdownNow();
>         }
>     }
> {noformat}
> So the problem appears to be that DatasetGraphWithLock claims multi-reader support but in reality does not allow this.

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira