/**
   * Private method that determines whether a given task should be re-tried based on the given
   * {@code Throwable} that caused failure. If this returns {@code true} then the task should be
   * re-tried. Otherwise, the task should be dropped.
   */
  private boolean shouldRetry(ScheduledTaskImpl task, Throwable t) {
    // NOTE: as a first-pass implementation this simply instructs the
    // caller to try again if retry is requested, but other strategies
    // (like the number of times re-tried) might be considered later
    if ((t instanceof ExceptionRetryStatus) && (((ExceptionRetryStatus) t).shouldRetry())) {
      return true;
    }

    // we're not re-trying the task, so log that it's being dropped
    if (logger.isLoggable(Level.WARNING)) {
      if (task.isRecurring()) {
        logger.logThrow(
            Level.WARNING,
            t,
            "skipping a recurrence of "
                + "a task that failed with a non-retryable "
                + "exception: {0}",
            task);
      } else {
        logger.logThrow(
            Level.WARNING,
            t,
            "dropping a task that " + "failed with a non-retryable exception: {0}",
            task);
      }
    }

    return false;
  }
  /**
   * Creates an instance of {@code TransactionSchedulerImpl}.
   *
   * @param properties the {@code Properties} for the system
   * @param transactionCoordinator the {@code TransactionCoordinator} used by the system to manage
   *     transactions
   * @param profileCollectorHandle the {@code ProfileCollectorHandler} used to manage collection of
   *     per-task profiling data
   * @param accessCoordinator the {@code AccessCoordinator} used by the system to managed shared
   *     data
   * @throws InvocationTargetException if there is a failure initializing the {@code SchedulerQueue}
   * @throws Exception if there is any failure creating the scheduler
   */
  TransactionSchedulerImpl(
      Properties properties,
      TransactionCoordinator transactionCoordinator,
      ProfileCollectorHandle profileCollectorHandle,
      AccessCoordinatorHandle accessCoordinator)
      throws Exception {
    logger.log(Level.CONFIG, "Creating a Transaction Scheduler");

    if (properties == null) {
      throw new NullPointerException("Properties cannot be null");
    }
    if (transactionCoordinator == null) {
      throw new NullPointerException("Coordinator cannot be null");
    }
    if (profileCollectorHandle == null) {
      throw new NullPointerException("Collector handle cannot be null");
    }
    if (accessCoordinator == null) {
      throw new NullPointerException("AccessCoordinator cannot be null");
    }

    this.transactionCoordinator = transactionCoordinator;
    this.profileCollectorHandle = profileCollectorHandle;
    this.accessCoordinator = accessCoordinator;

    String queueName = properties.getProperty(SCHEDULER_QUEUE_PROPERTY, DEFAULT_SCHEDULER_QUEUE);
    try {
      Class<?> queueClass = Class.forName(queueName);
      Constructor<?> queueCtor = queueClass.getConstructor(Properties.class);
      this.backingQueue = (SchedulerQueue) (queueCtor.newInstance(properties));
    } catch (InvocationTargetException e) {
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logThrow(
            Level.CONFIG, e.getCause(), "Queue {0} " + "failed to initialize", queueName);
      }
      throw e;
    } catch (Exception e) {
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logThrow(Level.CONFIG, e, "Queue {0} unavailable", queueName);
      }
      throw e;
    }

    // startup the requested number of consumer threads
    // NOTE: this is a simple implmentation to replicate the previous
    // behvavior, with the assumption that it will change if the
    // scheduler starts trying to add or drop consumers adaptively
    int requestedThreads =
        Integer.parseInt(
            properties.getProperty(CONSUMER_THREADS_PROPERTY, DEFAULT_CONSUMER_THREADS));
    if (logger.isLoggable(Level.CONFIG)) {
      logger.log(Level.CONFIG, "Using {0} transaction consumer threads", requestedThreads);
    }
    this.executor = Executors.newCachedThreadPool();
    for (int i = 0; i < requestedThreads; i++) {
      executor.submit(new TaskConsumer());
    }
  }
  /** {@inheritDoc} */
  public void doShutdown() {
    final IoFuture<?, ?> future = acceptFuture;
    acceptFuture = null;
    if (future != null) {
      future.cancel(true);
    }

    if (acceptor != null) {
      try {
        acceptor.close();
      } catch (IOException e) {
        logger.logThrow(Level.FINEST, e, "closing acceptor throws");
        // swallow exception
      }
    }

    if (asyncChannelGroup != null) {
      asyncChannelGroup.shutdown();
      boolean groupShutdownCompleted = false;
      try {
        groupShutdownCompleted = asyncChannelGroup.awaitTermination(1, TimeUnit.SECONDS);
      } catch (InterruptedException e) {
        logger.logThrow(Level.FINEST, e, "shutdown acceptor interrupted");
        Thread.currentThread().interrupt();
      }
      if (!groupShutdownCompleted) {
        logger.log(Level.WARNING, "forcing async group shutdown");
        try {
          asyncChannelGroup.shutdownNow();
        } catch (IOException e) {
          logger.logThrow(Level.FINEST, e, "shutdown acceptor throws");
          // swallow exception
        }
      }
    }
    logger.log(Level.FINEST, "acceptor shutdown");

    if (exporter != null) {
      try {
        exporter.unexport();
        logger.log(Level.FINEST, "client session server unexported");
      } catch (RuntimeException e) {
        logger.logThrow(Level.FINEST, e, "unexport server throws");
        // swallow exception
      }
    }

    for (ClientSessionHandler handler : handlers.values()) {
      handler.shutdown();
    }
    handlers.clear();

    flushContextsThread.interrupt();
  }
예제 #4
0
  /**
   * {@inheritDoc}
   *
   * <p>Enqueues a send event to this client session's event queue for servicing.
   */
  public ClientSession send(ByteBuffer message) {
    try {
      if (message.remaining() > SimpleSgsProtocol.MAX_PAYLOAD_LENGTH) {
        throw new IllegalArgumentException(
            "message too long: "
                + message.remaining()
                + " > "
                + SimpleSgsProtocol.MAX_PAYLOAD_LENGTH);
      } else if (!isConnected()) {
        throw new IllegalStateException("client session not connected");
      }
      /*
       * TODO: Possible optimization: if we have passed our own special
       * buffer to the app, we can detect that here and possibly avoid a
       * copy.  Our special buffer could be one we passed to the
       * receivedMessage callback, or we could add a special API to
       * pre-allocate buffers. -JM
       */
      ByteBuffer buf = ByteBuffer.wrap(new byte[1 + message.remaining()]);
      buf.put(SimpleSgsProtocol.SESSION_MESSAGE).put(message).flip();
      addEvent(new SendEvent(buf.array()));
      if (sessionService.sendMessageOp != null) {
        sessionService.sendMessageOp.report();
      }

      return this;

    } catch (RuntimeException e) {
      if (logger.isLoggable(Level.FINEST)) {
        logger.logThrow(
            Level.FINEST, e, "send message:{0} throws", HexDumper.format(message, 0x50));
      }
      throw e;
    }
  }
  /** {@inheritDoc} */
  public void doShutdown() {
    if (protocolAcceptor != null) {
      try {
        protocolAcceptor.close();
      } catch (IOException ignore) {
      }
    }
    for (ClientSessionHandler handler : handlers.values()) {
      handler.shutdown();
    }
    handlers.clear();

    if (exporter != null) {
      try {
        exporter.unexport();
        logger.log(Level.FINEST, "client session server unexported");
      } catch (RuntimeException e) {
        logger.logThrow(Level.FINEST, e, "unexport server throws");
        // swallow exception
      }
    }

    synchronized (flushContextsLock) {
      flushContextsLock.notifyAll();
    }
  }
예제 #6
0
  /** {@inheritDoc} */
  public Channel getChannel(String name) {
    try {
      return ChannelImpl.getInstance(name);

    } catch (RuntimeException e) {
      logger.logThrow(Level.FINEST, e, "getChannel:{0} throws");
      throw e;
    }
  }
예제 #7
0
  /** {@inheritDoc} */
  public Channel createChannel(String name, ChannelListener listener, Delivery delivery) {
    try {
      Channel channel = ChannelImpl.newInstance(name, listener, delivery, writeBufferSize);
      return channel;

    } catch (RuntimeException e) {
      logger.logThrow(Level.FINEST, e, "createChannel:{0} throws");
      throw e;
    }
  }
 /**
  * Returns a set of protocol descriptors for the specified {@code nodeId}, or {@code null} if
  * there are no descriptors for the node. This method must be run outside a transaction.
  */
 Set<ProtocolDescriptor> getProtocolDescriptors(long nodeId) {
   checkNonTransactionalContext();
   GetProtocolDescriptorsTask protocolDescriptorsTask = new GetProtocolDescriptorsTask(nodeId);
   try {
     transactionScheduler.runTask(protocolDescriptorsTask, taskOwner);
     return protocolDescriptorsTask.descriptors;
   } catch (Exception e) {
     logger.logThrow(Level.WARNING, e, "GetProtocolDescriptorsTask for node:{0} throws", nodeId);
     return null;
   }
 }
예제 #9
0
  /** {@inheritDoc} */
  protected void doShutdown() {
    logger.log(Level.FINEST, "shutdown");

    try {
      if (exporter != null) {
        exporter.unexport();
      }
    } catch (RuntimeException e) {
      logger.logThrow(Level.FINEST, e, "unexport server throws");
      // swallow exception
    }
  }
예제 #10
0
 /** {@inheritDoc} */
 public void run() {
   String channelServerKey = getChannelServerKey(nodeId);
   try {
     ManagedSerializable wrappedProxy =
         (ManagedSerializable) getDataService().getServiceBinding(channelServerKey);
     channelServer = (ChannelServer) wrappedProxy.get();
   } catch (NameNotBoundException e) {
     channelServer = null;
   } catch (ObjectNotFoundException e) {
     logger.logThrow(
         Level.SEVERE,
         e,
         "ChannelServer binding:{0} exists, but object removed",
         channelServerKey);
     channelServer = null;
   }
 }
예제 #11
0
  /**
   * Runs a transactional task to query the status of the node with the specified {@code nodeId} and
   * returns {@code true} if the node is alive and {@code false} otherwise.
   *
   * <p>This method must be called from outside a transaction or {@code IllegalStateException} will
   * be thrown.
   */
  boolean isAlive(long nodeId) {
    // Make sure that we're not in a transactional context.
    try {
      getTransaction();
      throw new IllegalStateException("isAlive called from a transactional context");
    } catch (TransactionNotActiveException e) {
    }

    try {
      CheckNodeStatusTask nodeStatus = new CheckNodeStatusTask(nodeId);
      transactionScheduler.runTask(nodeStatus, taskOwner);
      return nodeStatus.isAlive;
    } catch (Exception e) {
      if (logger.isLoggable(Level.WARNING)) {
        logger.logThrow(Level.WARNING, e, "running CheckNodeStatusTask throws");
      }
      // TBD: is this the correct value to return?
      return false;
    }
  }
  /** {@inheritDoc} */
  public void doReady() throws Exception {
    channelService = txnProxy.getService(ChannelServiceImpl.class);
    try {
      protocolAcceptor.accept(protocolListener);
    } catch (IOException e) {
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logThrow(Level.CONFIG, e, "Failed to start accepting connections");
      }
      throw e;
    }

    transactionScheduler.runTask(
        new AbstractKernelRunnable("AddProtocolDescriptorMapping") {
          public void run() {
            getProtocolDescriptorsMap()
                .put(localNodeId, Collections.singleton(protocolAcceptor.getDescriptor()));
          }
        },
        taskOwner);
  }
 /**
  * Returns the proxy for the client session server on the specified {@code nodeId}, or {@code
  * null} if no server exists.
  *
  * @param nodeId a node ID
  * @return the proxy for the client session server on the specified {@code nodeId}, or {@code
  *     null}
  */
 ClientSessionServer getClientSessionServer(long nodeId) {
   if (nodeId == localNodeId) {
     return serverImpl;
   } else {
     String sessionServerKey = getClientSessionServerKey(nodeId);
     try {
       ManagedSerializable wrappedProxy =
           (ManagedSerializable) dataService.getServiceBinding(sessionServerKey);
       return (ClientSessionServer) wrappedProxy.get();
     } catch (NameNotBoundException e) {
       return null;
     } catch (ObjectNotFoundException e) {
       logger.logThrow(
           Level.SEVERE,
           e,
           "ClientSessionServer binding:{0} exists, " + "but object removed",
           sessionServerKey);
       throw e;
     }
   }
 }
예제 #14
0
  /**
   * Creates each of the <code>Service</code>s in order, in preparation for starting up an
   * application. At completion, this schedules an <code>AppStartupRunner</code> to finish
   * application startup.
   */
  public void run() {
    if (logger.isLoggable(Level.CONFIG))
      logger.log(Level.CONFIG, "{0}: starting services", appName);

    // create an empty context and register with the scheduler
    ComponentRegistryImpl services = new ComponentRegistryImpl();
    ComponentRegistryImpl managers = new ComponentRegistryImpl();
    AppKernelAppContext ctx = new AppKernelAppContext(appName, services, managers);
    MasterTaskScheduler scheduler = systemRegistry.getComponent(MasterTaskScheduler.class);
    try {
      scheduler.registerApplication(ctx, appProperties);
    } catch (Exception e) {
      if (logger.isLoggable(Level.SEVERE))
        logger.logThrow(Level.SEVERE, e, "{0}: failed app scheduler " + "setup", appName);
      return;
    }

    // create the application's identity, and set as the current owner
    IdentityImpl id = new IdentityImpl("app:" + appName);
    TaskOwnerImpl owner = new TaskOwnerImpl(id, ctx);
    ThreadState.setCurrentOwner(owner);

    // get the managers and services that we're using
    HashSet<Object> managerSet = new HashSet<Object>();
    try {
      fetchServices(services, managerSet);
    } catch (Exception e) {
      if (logger.isLoggable(Level.SEVERE))
        logger.logThrow(Level.SEVERE, e, "{0}: failed to create " + "services", appName);

      ctx.shutdownServices();
      return;
    }

    // register any profiling managers and fill in the manager registry
    for (Object manager : managerSet) {
      if (profileRegistrar != null) {
        if (manager instanceof ProfileProducer)
          ((ProfileProducer) manager).setProfileRegistrar(profileRegistrar);
      }
      managers.addComponent(manager);
    }

    // with the managers created, setup the final context and owner
    ctx = new AppKernelAppContext(appName, services, managers);
    owner = new TaskOwnerImpl(id, ctx);
    ThreadState.setCurrentOwner(owner);

    // notify all of the services that the application state is ready
    try {
      for (Object s : services) ((Service) s).ready();
    } catch (Exception e) {
      logger.logThrow(
          Level.SEVERE,
          e,
          "{0}: failed when notifying services that application is " + "ready",
          appName);
      // shutdown all of the services
      ctx.shutdownServices();
      return;
    }

    // At this point the services are now created, so the final step
    // is to try booting the application by running a special
    // KernelRunnable in an unbounded transaction. Note that if we're
    // running as a "server" then we don't actually start an app
    if (!appProperties
        .getProperty(StandardProperties.APP_LISTENER)
        .equals(StandardProperties.APP_LISTENER_NONE)) {
      AppStartupRunner startupRunner = new AppStartupRunner(ctx, appProperties);
      UnboundedTransactionRunner unboundedTransactionRunner =
          new UnboundedTransactionRunner(startupRunner);
      try {
        if (logger.isLoggable(Level.CONFIG))
          logger.log(Level.CONFIG, "{0}: starting application", appName);
        // run the startup task, notifying the kernel on success
        scheduler.runTask(unboundedTransactionRunner, owner, true);
        kernel.contextReady(owner, true);
      } catch (Exception e) {
        if (logger.isLoggable(Level.CONFIG))
          logger.logThrow(Level.CONFIG, e, "{0}: failed to " + "start application", appName);
        return;
      }
    } else {
      // we're running without an application, so we're finished
      kernel.contextReady(owner, false);
    }

    if (logger.isLoggable(Level.CONFIG))
      logger.log(Level.CONFIG, "{0}: finished service config runner", appName);
  }
예제 #15
0
  /**
   * Private helper that creates the services and their associated managers, taking care to call out
   * the standard services first, because we need to get the ordering constant and make sure that
   * they're all present.
   */
  private void fetchServices(ComponentRegistryImpl services, HashSet<Object> managerSet)
      throws Exception {
    // before we start, figure out if we're running with only a sub-set
    // of services, in which case there should be no external services
    String finalService = appProperties.getProperty(StandardProperties.FINAL_SERVICE);
    StandardService finalStandardService = null;
    String externalServices = appProperties.getProperty(StandardProperties.SERVICES);
    String externalManagers = appProperties.getProperty(StandardProperties.MANAGERS);
    if (finalService != null) {
      if ((externalServices != null) || (externalManagers != null))
        throw new IllegalArgumentException(
            "Cannot specify external " + "services and a final " + "service");

      // validate the final service
      try {
        finalStandardService = Enum.valueOf(StandardService.class, finalService);
      } catch (IllegalArgumentException iae) {
        if (logger.isLoggable(Level.SEVERE))
          logger.logThrow(Level.SEVERE, iae, "Invalid final " + "service name: {0}", finalService);
        throw iae;
      }

      // make sure we're not running with an application
      if (!appProperties
          .getProperty(StandardProperties.APP_LISTENER)
          .equals(StandardProperties.APP_LISTENER_NONE))
        throw new IllegalArgumentException(
            "Cannot specify an app " + "listener and a final " + "service");
    } else {
      finalStandardService = StandardService.LAST_SERVICE;
    }

    // load the data service

    String dataServiceClass =
        appProperties.getProperty(StandardProperties.DATA_SERVICE, DEFAULT_DATA_SERVICE);
    String dataManagerClass =
        appProperties.getProperty(StandardProperties.DATA_MANAGER, DEFAULT_DATA_MANAGER);
    services.addComponent(setupService(dataServiceClass, dataManagerClass, managerSet));

    // load the watch-dog service, which has no associated manager

    if (StandardService.WatchdogService.ordinal() > finalStandardService.ordinal()) return;

    String watchdogServiceClass =
        appProperties.getProperty(StandardProperties.WATCHDOG_SERVICE, DEFAULT_WATCHDOG_SERVICE);
    Service watchdogService = createService(Class.forName(watchdogServiceClass));
    services.addComponent(watchdogService);
    if (watchdogService instanceof ProfileProducer) {
      if (profileRegistrar != null)
        ((ProfileProducer) watchdogService).setProfileRegistrar(profileRegistrar);
    }

    // load the node mapping service, which has no associated manager

    if (StandardService.NodeMappingService.ordinal() > finalStandardService.ordinal()) return;

    String nodemapServiceClass =
        appProperties.getProperty(
            StandardProperties.NODE_MAPPING_SERVICE, DEFAULT_NODE_MAPPING_SERVICE);
    Service nodemapService = createService(Class.forName(nodemapServiceClass));
    services.addComponent(nodemapService);
    if (nodemapService instanceof ProfileProducer) {
      if (profileRegistrar != null)
        ((ProfileProducer) nodemapService).setProfileRegistrar(profileRegistrar);
    }

    // load the task service

    if (StandardService.TaskService.ordinal() > finalStandardService.ordinal()) return;

    String taskServiceClass =
        appProperties.getProperty(StandardProperties.TASK_SERVICE, DEFAULT_TASK_SERVICE);
    String taskManagerClass =
        appProperties.getProperty(StandardProperties.TASK_MANAGER, DEFAULT_TASK_MANAGER);
    services.addComponent(setupService(taskServiceClass, taskManagerClass, managerSet));

    // load the client session service, which has no associated manager

    if (StandardService.ClientSessionService.ordinal() > finalStandardService.ordinal()) return;

    String clientSessionServiceClass =
        appProperties.getProperty(
            StandardProperties.CLIENT_SESSION_SERVICE, DEFAULT_CLIENT_SESSION_SERVICE);
    Service clientSessionService = createService(Class.forName(clientSessionServiceClass));
    services.addComponent(clientSessionService);
    if (clientSessionService instanceof ProfileProducer) {
      if (profileRegistrar != null)
        ((ProfileProducer) clientSessionService).setProfileRegistrar(profileRegistrar);
    }

    // load the channel service

    if (StandardService.ChannelService.ordinal() > finalStandardService.ordinal()) return;

    String channelServiceClass =
        appProperties.getProperty(StandardProperties.CHANNEL_SERVICE, DEFAULT_CHANNEL_SERVICE);
    String channelManagerClass =
        appProperties.getProperty(StandardProperties.CHANNEL_MANAGER, DEFAULT_CHANNEL_MANAGER);
    services.addComponent(setupService(channelServiceClass, channelManagerClass, managerSet));

    // finally, load any external services and their associated managers
    if ((externalServices != null) && (externalManagers != null)) {
      String[] serviceClassNames = externalServices.split(":", -1);
      String[] managerClassNames = externalManagers.split(":", -1);
      if (serviceClassNames.length != managerClassNames.length) {
        if (logger.isLoggable(Level.SEVERE))
          logger.log(
              Level.SEVERE,
              "External service count " + "({0}) does not match manager count ({1}).",
              serviceClassNames.length,
              managerClassNames.length);
        throw new IllegalArgumentException("Mis-matched service " + "and manager count");
      }

      for (int i = 0; i < serviceClassNames.length; i++) {
        if (!managerClassNames[i].equals("")) {
          services.addComponent(
              setupService(serviceClassNames[i], managerClassNames[i], managerSet));
        } else {
          Class<?> serviceClass = Class.forName(serviceClassNames[i]);
          Service service = createService(serviceClass);
          services.addComponent(service);
          if ((profileRegistrar != null) && (service instanceof ProfileProducer))
            ((ProfileProducer) service).setProfileRegistrar(profileRegistrar);
        }
      }
    }
  }
예제 #16
0
  /**
   * Invokes the {@code disconnected} callback on this session's {@code ClientSessionListener} (if
   * present and {@code notify} is {@code true}), removes the listener and its binding (if present),
   * and then removes this session and its bindings from the specified {@code dataService}. If the
   * bindings have already been removed from the {@code dataService} this method takes no action.
   * This method should only be called within a transaction.
   *
   * @param dataService a data service
   * @param graceful {@code true} if disconnection is graceful, and {@code false} otherwise
   * @param notify {@code true} if the {@code disconnected} callback should be invoked
   * @throws TransactionException if there is a problem with the current transaction
   */
  void notifyListenerAndRemoveSession(
      final DataService dataService, final boolean graceful, boolean notify) {
    String sessionKey = getSessionKey();
    String sessionNodeKey = getSessionNodeKey();
    String listenerKey = getListenerKey();
    String eventQueueKey = getEventQueueKey();

    /*
     * Get ClientSessionListener, and remove its binding and
     * wrapper if applicable.  The listener may not be bound
     * in the data service if: the AppListener.loggedIn callback
     * either threw a non-retryable exception or returned a
     * null listener, or the application removed the
     * ClientSessionListener object from the data service.
     */
    ClientSessionListener listener = null;
    try {
      ManagedObject obj = dataService.getServiceBinding(listenerKey);
      dataService.removeServiceBinding(listenerKey);
      if (obj instanceof ListenerWrapper) {
        dataService.removeObject(obj);
        listener = ((ListenerWrapper) obj).get();
      } else {
        listener = (ClientSessionListener) obj;
      }

    } catch (NameNotBoundException e) {
      logger.logThrow(Level.FINE, e, "removing ClientSessionListener for session:{0} throws", this);
    }

    /*
     * Remove event queue and associated binding.
     */
    try {
      ManagedObject eventQueue = dataService.getServiceBinding(eventQueueKey);
      dataService.removeServiceBinding(eventQueueKey);
      dataService.removeObject(eventQueue);
    } catch (NameNotBoundException e) {
      logger.logThrow(Level.FINE, e, "removing EventQueue for session:{0} throws", this);
    }

    /*
     * Invoke listener's 'disconnected' callback if 'notify'
     * is true and a listener exists for this client session.  If the
     * 'disconnected' callback throws a non-retryable exception,
     * schedule a task to remove this session and its associated
     * bindings without invoking the listener, and rethrow the
     * exception so that the currently executing transaction aborts.
     */
    if (notify && listener != null) {
      try {
        listener.disconnected(graceful);
      } catch (RuntimeException e) {
        if (!isRetryableException(e)) {
          logger.logThrow(
              Level.WARNING,
              e,
              "invoking disconnected callback on listener:{0} " + " for session:{1} throws",
              listener,
              this);
          sessionService.scheduleTask(
              new AbstractKernelRunnable() {
                public void run() {
                  ClientSessionImpl sessionImpl = ClientSessionImpl.getSession(dataService, id);
                  sessionImpl.notifyListenerAndRemoveSession(dataService, graceful, false);
                }
              },
              identity);
        }
        throw e;
      }
    }

    /*
     * Remove this session's state and bindings.
     */
    try {
      dataService.removeServiceBinding(sessionKey);
      dataService.removeServiceBinding(sessionNodeKey);
      dataService.removeObject(this);
    } catch (NameNotBoundException e) {
      logger.logThrow(Level.WARNING, e, "session binding already removed:{0}", sessionKey);
    }

    /*
     * Remove this session's wrapper object, if it still exists.
     */
    try {
      dataService.removeObject(wrappedSessionRef.get());
    } catch (ObjectNotFoundException e) {
      // already removed
    }
  }
  /**
   * Constructs an instance of this class with the specified properties.
   *
   * @param properties service properties
   * @param systemRegistry system registry
   * @param txnProxy transaction proxy
   * @throws Exception if a problem occurs when creating the service
   */
  public ClientSessionServiceImpl(
      Properties properties, ComponentRegistry systemRegistry, TransactionProxy txnProxy)
      throws Exception {
    super(properties, systemRegistry, txnProxy, logger);

    logger.log(Level.CONFIG, "Creating ClientSessionServiceImpl properties:{0}", properties);
    PropertiesWrapper wrappedProps = new PropertiesWrapper(properties);

    try {
      appPort = wrappedProps.getRequiredIntProperty(StandardProperties.APP_PORT, 1, 65535);

      /*
       * Get the property for controlling session event processing.
       */
      eventsPerTxn =
          wrappedProps.getIntProperty(
              EVENTS_PER_TXN_PROPERTY, DEFAULT_EVENTS_PER_TXN, 1, Integer.MAX_VALUE);

      readBufferSize =
          wrappedProps.getIntProperty(
              READ_BUFFER_SIZE_PROPERTY, DEFAULT_READ_BUFFER_SIZE, 8192, Integer.MAX_VALUE);

      writeBufferSize =
          wrappedProps.getIntProperty(
              WRITE_BUFFER_SIZE_PROPERTY, DEFAULT_WRITE_BUFFER_SIZE, 8192, Integer.MAX_VALUE);

      /*
       * Export the ClientSessionServer.
       */
      int serverPort =
          wrappedProps.getIntProperty(SERVER_PORT_PROPERTY, DEFAULT_SERVER_PORT, 0, 65535);
      serverImpl = new SessionServerImpl();
      exporter = new Exporter<ClientSessionServer>(ClientSessionServer.class);
      try {
        int port = exporter.export(serverImpl, serverPort);
        serverProxy = exporter.getProxy();
        if (logger.isLoggable(Level.CONFIG)) {
          logger.log(Level.CONFIG, "export successful. port:{0,number,#}", port);
        }
      } catch (Exception e) {
        try {
          exporter.unexport();
        } catch (RuntimeException re) {
        }
        throw e;
      }

      /*
       * Get services and initialize service-related and other
       * instance fields.
       */
      identityManager = systemRegistry.getComponent(IdentityCoordinator.class);
      flushContextsThread.start();
      contextFactory = new ContextFactory(txnProxy);
      watchdogService = txnProxy.getService(WatchdogService.class);
      nodeMapService = txnProxy.getService(NodeMappingService.class);
      taskService = txnProxy.getService(TaskService.class);
      localNodeId = watchdogService.getLocalNodeId();
      watchdogService.addRecoveryListener(new ClientSessionServiceRecoveryListener());
      int acceptorBacklog =
          wrappedProps.getIntProperty(ACCEPTOR_BACKLOG_PROPERTY, DEFAULT_ACCEPTOR_BACKLOG);

      /*
       * Check service version.
       */
      transactionScheduler.runTask(
          new AbstractKernelRunnable() {
            public void run() {
              checkServiceVersion(VERSION_KEY, MAJOR_VERSION, MINOR_VERSION);
            }
          },
          taskOwner);

      /*
       * Store the ClientSessionServer proxy in the data store.
       */
      transactionScheduler.runTask(
          new AbstractKernelRunnable() {
            public void run() {
              dataService.setServiceBinding(
                  getClientSessionServerKey(localNodeId),
                  new ManagedSerializable<ClientSessionServer>(serverProxy));
            }
          },
          taskOwner);

      /*
       * Listen for incoming client connections.
       */
      InetSocketAddress listenAddress = new InetSocketAddress(appPort);
      AsynchronousChannelProvider provider =
          // TODO fetch from config
          AsynchronousChannelProvider.provider();
      asyncChannelGroup =
          // TODO fetch from config
          provider.openAsynchronousChannelGroup(Executors.newCachedThreadPool());
      acceptor = provider.openAsynchronousServerSocketChannel(asyncChannelGroup);
      try {
        acceptor.bind(listenAddress, acceptorBacklog);
        if (logger.isLoggable(Level.CONFIG)) {
          logger.log(Level.CONFIG, "bound to port:{0,number,#}", getListenPort());
        }
      } catch (Exception e) {
        logger.logThrow(Level.WARNING, e, "acceptor failed to listen on {0}", listenAddress);
        try {
          acceptor.close();
        } catch (IOException ioe) {
          logger.logThrow(Level.WARNING, ioe, "problem closing acceptor");
        }
        throw e;
      }
      // TBD: listen for UNRELIABLE connections as well?

    } catch (Exception e) {
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logThrow(Level.CONFIG, e, "Failed to create ClientSessionServiceImpl");
      }
      doShutdown();
      throw e;
    }
  }
  /**
   * Private method that executes a single task, creating the transaction state and handling re-try
   * as appropriate. If the thread calling this method is interrupted before the task can complete
   * then this method attempts to re-schedule the task to run in another thread if {@code
   * retryOnInterruption} is {@code true} and always re-throws the associated {@code
   * InterruptedException}. Providing {@code true} for the {@code unbounded} parameter results in a
   * transaction with timeout value as specified by the value of the {@code
   * TransactionCoordinator.TXN_UNBOUNDED_TIMEOUT_PROPERTY} property.
   *
   * <p>This method returns {@code true} if the task was completed or failed permanently, and {@code
   * false} otherwise. If {@code false} is returned then the task is scheduled to be re-tried at
   * some point in the future, possibly by another thread, by this method. The caller may query the
   * status of the task and wait for the task to complete or fail permanently through the {@code
   * ScheduledTaskImpl} interface.
   */
  private boolean executeTask(
      ScheduledTaskImpl task, boolean unbounded, boolean retryOnInterruption)
      throws InterruptedException {
    logger.log(Level.FINEST, "starting a new transactional task");

    // store the current owner, and then push the new thread detail
    Identity parent = ContextResolver.getCurrentOwner();
    ContextResolver.setTaskState(kernelContext, task.getOwner());

    try {
      // keep trying to run the task until we succeed, tracking how
      // many tries it actually took
      while (true) {
        if (!task.setRunning(true)) {
          // this task is already finished
          return true;
        }

        // NOTE: We could report the two queue sizes separately,
        // so we should figure out how we want to represent these
        int waitSize = backingQueue.getReadyCount() + dependencyCount.get();
        profileCollectorHandle.startTask(
            task.getTask(), task.getOwner(), task.getStartTime(), waitSize);
        task.incrementTryCount();

        Transaction transaction = null;

        try {
          // setup the transaction state
          TransactionHandle handle = transactionCoordinator.createTransaction(unbounded);
          transaction = handle.getTransaction();
          ContextResolver.setCurrentTransaction(transaction);

          try {
            // notify the profiler and access coordinator
            profileCollectorHandle.noteTransactional(transaction.getId());
            accessCoordinator.notifyNewTransaction(
                transaction, task.getStartTime(), task.getTryCount());

            // run the task in the new transactional context
            task.getTask().run();
          } finally {
            // regardless of the outcome, always clear the current
            // transaction state before proceeding...
            ContextResolver.clearCurrentTransaction(transaction);
          }

          // try to commit the transaction...note that there's the
          // chance that the application code masked the orginal
          // cause of a failure, so we'll check for that first,
          // re-throwing the root cause in that case
          if (transaction.isAborted()) {
            throw transaction.getAbortCause();
          }
          handle.commit();

          // the task completed successfully, so we're done
          profileCollectorHandle.finishTask(task.getTryCount());
          task.setDone(null);
          return true;
        } catch (InterruptedException ie) {
          // make sure the transaction was aborted
          if (!transaction.isAborted()) {
            transaction.abort(ie);
          }
          profileCollectorHandle.finishTask(task.getTryCount(), ie);
          // if the task didn't finish because of the interruption
          // then we want to note that and possibly re-queue the
          // task to run in a usable thread
          if (task.setInterrupted() && retryOnInterruption) {
            if (!handoffRetry(task, ie)) {
              // if the task couldn't be re-queued, then there's
              // nothing left to do but drop it
              task.setDone(ie);
              if (logger.isLoggable(Level.WARNING)) {
                logger.logThrow(Level.WARNING, ie, "dropping " + "an interrupted task: {0}" + task);
              }
            }
          }
          // always re-throw the interruption
          throw ie;
        } catch (Throwable t) {
          // make sure the transaction was aborted
          if ((transaction != null) && (!transaction.isAborted())) {
            transaction.abort(t);
          }
          profileCollectorHandle.finishTask(task.getTryCount(), t);
          // some error occurred, so see if we should re-try
          if (!shouldRetry(task, t)) {
            // the task is not being re-tried
            task.setDone(t);
            return true;
          } else {
            // see if the re-try should be handed-off
            task.setRunning(false);
            if (handoffRetry(task, t)) {
              return false;
            }
          }
        }
      }
    } finally {
      // always restore the previous owner before leaving...
      ContextResolver.setTaskState(kernelContext, parent);
    }
  }
  /**
   * Constructs an instance of this class with the specified properties.
   *
   * @param properties service properties
   * @param systemRegistry system registry
   * @param txnProxy transaction proxy
   * @throws Exception if a problem occurs when creating the service
   */
  public ClientSessionServiceImpl(
      Properties properties, ComponentRegistry systemRegistry, TransactionProxy txnProxy)
      throws Exception {
    super(properties, systemRegistry, txnProxy, logger);
    logger.log(Level.CONFIG, "Creating ClientSessionServiceImpl properties:{0}", properties);
    PropertiesWrapper wrappedProps = new PropertiesWrapper(properties);
    try {
      /*
       * Get the property for controlling session event processing
       * and connection disconnection.
       */
      writeBufferSize =
          wrappedProps.getIntProperty(
              WRITE_BUFFER_SIZE_PROPERTY, DEFAULT_WRITE_BUFFER_SIZE, 8192, Integer.MAX_VALUE);
      eventsPerTxn =
          wrappedProps.getIntProperty(
              EVENTS_PER_TXN_PROPERTY, DEFAULT_EVENTS_PER_TXN, 1, Integer.MAX_VALUE);
      allowNewLogin = wrappedProps.getBooleanProperty(ALLOW_NEW_LOGIN_PROPERTY, false);

      /* Export the ClientSessionServer. */
      int serverPort =
          wrappedProps.getIntProperty(SERVER_PORT_PROPERTY, DEFAULT_SERVER_PORT, 0, 65535);
      serverImpl = new SessionServerImpl();
      exporter = new Exporter<ClientSessionServer>(ClientSessionServer.class);
      try {
        int port = exporter.export(serverImpl, serverPort);
        serverProxy = exporter.getProxy();
        if (logger.isLoggable(Level.CONFIG)) {
          logger.log(Level.CONFIG, "export successful. port:{0,number,#}", port);
        }
      } catch (Exception e) {
        try {
          exporter.unexport();
        } catch (RuntimeException re) {
        }
        throw e;
      }

      /* Get services and check service version. */
      flushContextsThread.start();
      contextFactory = new ContextFactory(txnProxy);
      watchdogService = txnProxy.getService(WatchdogService.class);
      nodeMapService = txnProxy.getService(NodeMappingService.class);
      taskService = txnProxy.getService(TaskService.class);
      localNodeId = watchdogService.getLocalNodeId();
      watchdogService.addRecoveryListener(new ClientSessionServiceRecoveryListener());

      transactionScheduler.runTask(
          new AbstractKernelRunnable("CheckServiceVersion") {
            public void run() {
              checkServiceVersion(VERSION_KEY, MAJOR_VERSION, MINOR_VERSION);
            }
          },
          taskOwner);

      /* Store the ClientSessionServer proxy in the data store. */
      transactionScheduler.runTask(
          new AbstractKernelRunnable("StoreClientSessionServiceProxy") {
            public void run() {
              dataService.setServiceBinding(
                  getClientSessionServerKey(localNodeId),
                  new ManagedSerializable<ClientSessionServer>(serverProxy));
            }
          },
          taskOwner);

      /*
       * Create the protocol listener and acceptor.
       */
      protocolListener = new ProtocolListenerImpl();

      protocolAcceptor =
          wrappedProps.getClassInstanceProperty(
              PROTOCOL_ACCEPTOR_PROPERTY,
              DEFAULT_PROTOCOL_ACCEPTOR,
              ProtocolAcceptor.class,
              new Class[] {Properties.class, ComponentRegistry.class, TransactionProxy.class},
              properties,
              systemRegistry,
              txnProxy);

      assert protocolAcceptor != null;

      /* Create our service profiling info and register our MBean */
      ProfileCollector collector = systemRegistry.getComponent(ProfileCollector.class);
      serviceStats = new ClientSessionServiceStats(collector);
      try {
        collector.registerMBean(serviceStats, ClientSessionServiceStats.MXBEAN_NAME);
      } catch (JMException e) {
        logger.logThrow(Level.CONFIG, e, "Could not register MBean");
      }

      /* Set the protocol descriptor in the ConfigMXBean. */
      ConfigManager config =
          (ConfigManager) collector.getRegisteredMBean(ConfigManager.MXBEAN_NAME);
      if (config == null) {
        logger.log(Level.CONFIG, "Could not find ConfigMXBean");
      } else {
        config.setProtocolDescriptor(protocolAcceptor.getDescriptor().toString());
      }

    } catch (Exception e) {
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logThrow(Level.CONFIG, e, "Failed to create ClientSessionServiceImpl");
      }
      doShutdown();
      throw e;
    }
  }
예제 #20
0
  /**
   * Constructs an instance of this class with the specified {@code properties}, {@code
   * systemRegistry}, and {@code txnProxy}.
   *
   * @param properties service properties
   * @param systemRegistry system registry
   * @param txnProxy transaction proxy
   * @throws Exception if a problem occurs when creating the service
   */
  public ChannelServiceImpl(
      Properties properties, ComponentRegistry systemRegistry, TransactionProxy txnProxy)
      throws Exception {
    super(properties, systemRegistry, txnProxy, logger);

    logger.log(Level.CONFIG, "Creating ChannelServiceImpl properties:{0}", properties);
    PropertiesWrapper wrappedProps = new PropertiesWrapper(properties);

    try {
      synchronized (ChannelServiceImpl.class) {
        if (contextMap == null) {
          contextMap = new TransactionContextMap<Context>(txnProxy);
        }
      }
      contextFactory = new ContextFactory(contextMap);
      WatchdogService watchdogService = txnProxy.getService(WatchdogService.class);
      sessionService = txnProxy.getService(ClientSessionService.class);
      localNodeId = watchdogService.getLocalNodeId();

      writeBufferSize =
          wrappedProps.getIntProperty(
              WRITE_BUFFER_SIZE_PROPERTY, DEFAULT_WRITE_BUFFER_SIZE, 8192, Integer.MAX_VALUE);
      /*
       * Get the property for controlling channel event processing.
       */
      eventsPerTxn =
          wrappedProps.getIntProperty(
              EVENTS_PER_TXN_PROPERTY, DEFAULT_EVENTS_PER_TXN, 1, Integer.MAX_VALUE);

      /*
       * Export the ChannelServer.
       */
      int serverPort =
          wrappedProps.getIntProperty(SERVER_PORT_PROPERTY, DEFAULT_SERVER_PORT, 0, 65535);
      serverImpl = new ChannelServerImpl();
      exporter = new Exporter<ChannelServer>(ChannelServer.class);
      try {
        int port = exporter.export(serverImpl, serverPort);
        serverProxy = exporter.getProxy();
        logger.log(Level.CONFIG, "ChannelServer export successful. port:{0,number,#}", port);
      } catch (Exception e) {
        try {
          exporter.unexport();
        } catch (RuntimeException re) {
        }
        throw e;
      }

      /*
       * Check service version.
       */
      transactionScheduler.runTask(
          new AbstractKernelRunnable() {
            public void run() {
              checkServiceVersion(VERSION_KEY, MAJOR_VERSION, MINOR_VERSION);
            }
          },
          taskOwner);

      /*
       * Store the ChannelServer proxy in the data store.
       */
      transactionScheduler.runTask(
          new AbstractKernelRunnable() {
            public void run() {
              dataService.setServiceBinding(
                  getChannelServerKey(localNodeId),
                  new ManagedSerializable<ChannelServer>(serverProxy));
            }
          },
          taskOwner);

      /*
       * Add listeners for handling recovery and for receiving
       * notification of client session disconnection.
       */
      watchdogService.addRecoveryListener(new ChannelServiceRecoveryListener());

      watchdogService.addNodeListener(new ChannelServiceNodeListener());

      sessionService.registerSessionDisconnectListener(new ChannelSessionDisconnectListener());

    } catch (Exception e) {
      if (logger.isLoggable(Level.CONFIG)) {
        logger.logThrow(Level.CONFIG, e, "Failed to create ChannelServiceImpl");
      }
      doShutdown();
      throw e;
    }
  }