public void close() { // mark the service for destruction if (!state.compareAndSet(State.ALIVE, State.NEED_DESTRUCTION)) { return; } // if we can get the lock, attempt a clean shutdown; otherwise someone else will shutdown try (DriverLockResult lockResult = tryLockAndProcessPendingStateChanges(0, TimeUnit.MILLISECONDS)) { // if we did not get the lock, interrupt the lock holder if (!lockResult.wasAcquired()) { // there is a benign race condition here were the lock holder // can be change between attempting to get lock and grabbing // the synchronized lock here, but in either case we want to // interrupt the lock holder thread synchronized (this) { if (lockHolder != null) { lockHolder.interrupt(); } } } // clean shutdown is automatically triggered during lock release } }
public boolean isFinished() { checkLockNotHeld("Can not check finished status while holding the driver lock"); // if we can get the lock, attempt a clean shutdown; otherwise someone else will shutdown try (DriverLockResult lockResult = tryLockAndProcessPendingStateChanges(0, TimeUnit.MILLISECONDS)) { if (lockResult.wasAcquired()) { boolean finished = state.get() != State.ALIVE || driverContext.isDone() || operators.get(operators.size() - 1).isFinished(); if (finished) { state.compareAndSet(State.ALIVE, State.NEED_DESTRUCTION); } return finished; } else { // did not get the lock, so we can't check operators, or destroy return state.get() != State.ALIVE || driverContext.isDone(); } } }
public ListenableFuture<?> process() { checkLockNotHeld("Can not process while holding the driver lock"); try (DriverLockResult lockResult = tryLockAndProcessPendingStateChanges(100, TimeUnit.MILLISECONDS)) { try { if (!lockResult.wasAcquired()) { // this is unlikely to happen unless the driver is being // destroyed and in that case the caller should notice notice // this state change by calling isFinished return NOT_BLOCKED; } driverContext.start(); if (!newSources.isEmpty()) { processNewSources(); } for (int i = 0; i < operators.size() - 1 && !driverContext.isDone(); i++) { // check if current operator is blocked Operator current = operators.get(i); ListenableFuture<?> blocked = current.isBlocked(); if (!blocked.isDone()) { current.getOperatorContext().recordBlocked(blocked); return blocked; } // check if next operator is blocked Operator next = operators.get(i + 1); blocked = next.isBlocked(); if (!blocked.isDone()) { next.getOperatorContext().recordBlocked(blocked); return blocked; } // if current operator is finished... if (current.isFinished()) { // let next operator know there will be no more data next.getOperatorContext().startIntervalTimer(); next.finish(); next.getOperatorContext().recordFinish(); } else { // if next operator needs input... if (next.needsInput()) { // get an output page from current operator current.getOperatorContext().startIntervalTimer(); Page page = current.getOutput(); current.getOperatorContext().recordGetOutput(page); // if we got an output page, add it to the next operator if (page != null) { next.getOperatorContext().startIntervalTimer(); next.addInput(page); next.getOperatorContext().recordAddInput(page); } } } } return NOT_BLOCKED; } catch (Throwable t) { driverContext.failed(t); throw t; } } }