Perhaps a strategy could insert interrupt checks in appropriate places,
avoiding inner loops, or perhaps refactoring them into two-level loops
where we check for interrupt on the outer level.

On Fri, Oct 16, 2015 at 6:58 AM, Marko Rodriguez <okramma...@gmail.com>
wrote:

> Hi,
>
> This is a scary body of work as processNextStarts() is not just in the
> base steps MapStep/FlatMapStep/BranchStep/etc., but littered throughout
> where extensions to the base steps are not easily done (e.g. barriers,
> etc.). Next, benchmark --- for every next there is an interrupt check
> (eek!).
>
> The idea of being able to interrupt a Traversal is nice, but the
> implementation and performance details are probably going to prove daunting.
>
> Marko.
>
> http://markorodriguez.com
>
> On Oct 16, 2015, at 5:31 AM, Daniel Kuppitz <m...@gremlin.guru> wrote:
>
> > This is a nice one. Once we have that in place, we can probably/hopefully
> > also provide a hotkey to gracefully cancel queries in the REPL (w/o
> having
> > to exit the console itself).
> >
> > Cheers,
> > Daniel
> >
> >
> > On Fri, Oct 16, 2015 at 1:05 PM, Stephen Mallette <spmalle...@gmail.com>
> > wrote:
> >
> >> I'm going to frame this in the context of Gremlin Server but I think
> this
> >> issue generally applies to any threaded application development done
> with
> >> TinkerPop.
> >>
> >> Gremlin Server does a number of things to protect itself from crazy
> scripts
> >> (i.e. long run scripts that may have been accidentally or maliciously
> sent
> >> to it).  The one thing it doesn't do perfectly is properly kill running
> >> scripts in the midst of a long run traversal.  It attempts to stop a
> >> running script by interrupting the thread that is processing it, but if
> the
> >> thread is at a point in the script that doesn't respect
> Thread.interrupt(),
> >> it basically just chews up that thread until it reaches a spot that
> does.
> >>
> >> I think Traversal could do a better job respecting interrupts.  Put in
> code
> >> speak, we should look to get this test to pass for all steps:
> >>
> >> @Test
> >> public void shouldRespectThreadInterruption() throws Exception {
> >>    final AtomicBoolean exceptionThrown = new AtomicBoolean(false);
> >>    final CountDownLatch startedIterating = new CountDownLatch(1000);
> >>    final List<Integer> l = IntStream.range(0,
> >> 1000000).boxed().collect(Collectors.toList());
> >>
> >>    final Thread t = new Thread(() -> {
> >>        try {
> >>            __.inject(l).unfold().sideEffect(i ->
> >> startedIterating.countDown()).iterate();
> >>            fail("Should have respected the thread interrupt");
> >>        } catch (Exception ie) {
> >>            exceptionThrown.set(ie instanceof RuntimeException);
> >>        }
> >>    });
> >>
> >>    t.start();
> >>
> >>    startedIterating.await();
> >>    t.interrupt();
> >>
> >>    t.join();
> >>    assertThat(exceptionThrown.get(), CoreMatchers.is(true));
> >> }
> >>
> >> Two things to note...First, the changes to make this test pass
> shouldn't be
> >> "big".  I got this test to pass with the addition of this line of code
> in
> >> FlatMapStep.processNextStart() on the first line after the start of the
> >> while(true).
> >>
> >> if(Thread.interrupted) throw new RuntimeException();
> >>
> >> That single line inserted in the right places should get interrupt
> working
> >> properly across Traversal.
> >>
> >> Second, note that I'm throwing/asserting RuntimeException.  I probably
> >> should be throwing a InterruptedException but that is a checked
> exception
> >> and that would really pollute up our Traversal code.  So, my suggestion
> is
> >> to create our own "InterruptedRuntimeException" that we can trap
> separately
> >> that would potentially wrap an actual InterruptedException.
> >>
> >> I'd like to tack this issue in to 3.1.0 if possible - please let me know
> >> your thoughts if you have any.
> >>
>
>

Reply via email to