Esempio n. 1
1
  /**
   * Disconnect a mavlink connection. If the operation is successful, it will be reported through
   * the MavLinkConnectionListener interface.
   */
  public void disconnect() {
    if (mConnectionStatus.get() == MAVLINK_DISCONNECTED
        || (mConnectThread == null && mTaskThread == null)) {
      return;
    }

    try {
      final long disconnectTime = System.currentTimeMillis();

      mConnectionStatus.set(MAVLINK_DISCONNECTED);
      mConnectionTime.set(-1);

      if (mConnectThread != null && mConnectThread.isAlive() && !mConnectThread.isInterrupted()) {
        mConnectThread.interrupt();
      }

      if (mTaskThread != null && mTaskThread.isAlive() && !mTaskThread.isInterrupted()) {
        mTaskThread.interrupt();
      }

      closeConnection();
      reportDisconnect(disconnectTime);
    } catch (IOException e) {
      mLogger.logErr(TAG, e);
      reportComError(e.getMessage());
    }
  }
 private void setNextIterThreadCount() {
   indexingCount.set(0);
   maxThreadCountPerIter.set(TestUtil.nextInt(random(), 1, MAX_THREADS_AT_ONCE));
   if (VERBOSE) {
     System.out.println("TEST: iter set maxThreadCount=" + maxThreadCountPerIter.get());
   }
 }
Esempio n. 3
0
  // 由于控制不用非常精确, 因此忽略此处的并发问题
  public static boolean isLog() {
    // System.out.println(count.get() + ", " + beginTime + ", " + punishTimeEnd + ", " +
    // System.currentTimeMillis());

    // 不写日志阶段
    if (punishTimeEnd > 0 && punishTimeEnd > System.currentTimeMillis()) {
      return false;
    }

    // 重新计数
    if (count.getAndIncrement() == 0) {
      beginTime = System.currentTimeMillis();
      return true;
    } else { // 已在计数
      // 超过阀门值, 设置count为0并设置一段时间内不写日志
      if (count.get() > ERROR_THRESHOLD) {
        count.set(0);
        punishTimeEnd = PUNISH_TIME + System.currentTimeMillis();
        return false;
      }
      // 没超过阀门值, 且当前时间已超过计数周期,则重新计算
      else if (System.currentTimeMillis() > (beginTime + INTERVAL)) {
        count.set(0);
      }

      return true;
    }
  }
Esempio n. 4
0
 protected Object verifyArg(
     CommandSender sender,
     Class<?> clazz,
     Command command,
     String[] args,
     int curIndex,
     AtomicInteger numUsedStrings) {
   numUsedStrings.set(0);
   if (Command.class == clazz) {
     return command;
   }
   String string = args[curIndex];
   if (string == null) throw new ArrayIndexOutOfBoundsException();
   numUsedStrings.set(1);
   if (Player.class == clazz) {
     return verifyPlayer(string);
   } else if (OfflinePlayer.class == clazz) {
     return verifyOfflinePlayer(string);
   } else if (String.class == clazz) {
     return string;
   } else if (Integer.class == clazz || int.class == clazz) {
     return verifyInteger(string);
   } else if (Boolean.class == clazz || boolean.class == clazz) {
     return Boolean.parseBoolean(string);
   } else if (Object.class == clazz) {
     return string;
   } else if (Float.class == clazz || float.class == clazz) {
     return verifyFloat(string);
   } else if (Double.class == clazz || double.class == clazz) {
     return verifyDouble(string);
   }
   return null;
 }
  @Override
  public void reset(int size) {
    // reset allocations/frees count first, as it's not used
    // for any functionality but to show information
    metrics.reset();

    // --- used
    try {
      usedLock.writeLock().lock();
      used.clear();
      usedMemorySize.set(0);
    } finally {
      usedLock.writeLock().unlock();
    }
    metrics.mark("vmtable.usedSize", usedMemorySize.longValue());
    metrics.mark("vmtable.usedBlocksCount", used.size());

    // --- free
    try {
      freeLock.writeLock().lock();
      free.clear();
      free.add(new TableBlock(0, size));
      freeMemorySize.set(size);
    } finally {
      freeLock.writeLock().unlock();
    }
    metrics.mark("vmtable.freeSize", freeMemorySize.longValue());
    metrics.mark("vmtable.freeBlocksCount", free.size());
  }
 public void resetStats() {
   pages.clear();
   completedRequests.set(0);
   finishedBuffers.set(0);
   failedBuffers.set(0);
   failure.set(null);
 }
  public void executeBatchNodeCmd(SQLCtrlCommand cmdHandler) {
    this.cmdHandler = cmdHandler;
    final int initCount = session.getTargetCount();
    runningCount.set(initCount);
    nodeCount = initCount;
    failed.set(false);
    faileCount.set(0);
    // 执行
    int started = 0;
    for (RouteResultsetNode rrn : session.getTargetKeys()) {
      if (rrn == null) {
        LOGGER.error("null is contained in RoutResultsetNodes, source = " + session.getSource());
        continue;
      }
      final BackendConnection conn = session.getTarget(rrn);
      if (conn != null) {
        conn.setResponseHandler(this);
        cmdHandler.sendCommand(session, conn);
        ++started;
      }
    }

    if (started < nodeCount) {
      runningCount.set(started);
      LOGGER.warn("some connection failed to execut " + (nodeCount - started));
      /**
       * assumption: only caused by front-end connection close. <br>
       * Otherwise, packet must be returned to front-end
       */
      failed.set(true);
    }
  }
Esempio n. 8
0
 /** Resets all the performance counters. */
 public void resetPerformanceCounters() {
   classLoadingCount.set(0);
   classLoadingTime.set(0);
   classLoadingPrefetchCacheCount.set(0);
   resourceLoadingCount.set(0);
   resourceLoadingTime.set(0);
 }
Esempio n. 9
0
 private String api_getTokenType(Account account, String token, boolean liveToken)
     throws Exception {
   synchronized (account) {
     try {
       String tokenType = account.getStringProperty("tokenType", null);
       if (tokenType != null && liveToken == false) return tokenType;
       br.getPage("http://cloudzer.net/api/user/jdownloader?access_token=" + token);
       tokenType = br.getRegex("account_type\":\\s*?\"(premium|free)").getMatch(0);
       if (tokenType == null) handleErrorCode(br, account, token, true);
       account.setProperty("tokenType", tokenType);
       if ("premium".equals(tokenType)) {
         try {
           maxPrem.set(-1);
           account.setMaxSimultanDownloads(-1);
           account.setConcurrentUsePossible(true);
         } catch (final Throwable e) {
         }
       } else {
         try {
           maxPrem.set(1);
           account.setMaxSimultanDownloads(1);
           account.setConcurrentUsePossible(false);
         } catch (final Throwable e) {
         }
       }
       return tokenType;
     } catch (final PluginException e) {
       maxPrem.set(-1);
       account.setProperty("token", null);
       account.setProperty("tokenType", null);
       throw e;
     }
   }
 }
Esempio n. 10
0
  public SpoutEntity(
      SpoutEngine engine,
      Transform transform,
      Controller controller,
      int viewDistance,
      UUID uid,
      boolean load) {
    id.set(NOTSPAWNEDID);
    this.transform.set(transform);

    if (uid != null) {
      this.uid = uid;
    } else {
      this.uid = UUID.randomUUID();
    }

    chunkLive = new AtomicReference<Chunk>();
    entityManagerLive = new AtomicReference<EntityManager>();
    controllerLive = new AtomicReference<Controller>();

    if (transform != null && load) {
      chunkLive.set(transform.getPosition().getWorld().getChunkFromBlock(transform.getPosition()));
      entityManagerLive.set(((SpoutRegion) chunkLive.get().getRegion()).getEntityManager());
    }

    viewDistanceLive.set(viewDistance);

    controllerLive.set(controller);
    if (controller != null) {
      controller.attachToEntity(this);
      if (controller instanceof PlayerController) {
        setObserver(true);
      }
    }
  }
 @Override
 public void run() {
   if (isTraceEnabled) logger.trace("Tripper triggered.");
   if (ques[1 - curQue.get()].isEmpty()) {
     curQue.set(-1);
   } else curQue.set(1 - curQue.get());
 }
 /** get returns the last value set */
 public void testGetSet() {
   AtomicInteger ai = new AtomicInteger(1);
   assertEquals(1, ai.get());
   ai.set(2);
   assertEquals(2, ai.get());
   ai.set(-3);
   assertEquals(-3, ai.get());
 }
Esempio n. 13
0
 @SuppressWarnings("deprecation")
 @Override
 public AccountInfo fetchAccountInfo(final Account account) throws Exception {
   final AccountInfo ai = new AccountInfo();
   /* reset maxPrem workaround on every fetchaccount info */
   MAXPREM.set(1);
   try {
     login(account, true);
   } catch (final PluginException e) {
     account.setValid(false);
     throw e;
   }
   if (!br.containsHTML("class=\"badge badge\\-success\">(?:PAID USER|USUARIO DE PAGO)</span>")) {
     account.setType(AccountType.FREE);
     account.setMaxSimultanDownloads(account_FREE_MAXDOWNLOADS);
     /* All accounts get the same (IP-based) downloadlimits --> Simultan free account usage makes no sense! */
     account.setConcurrentUsePossible(false);
     MAXPREM.set(account_FREE_MAXDOWNLOADS);
     ai.setStatus("Registered (free) account");
   } else {
     br.getPage("http://" + this.getHost() + "/upgrade." + type);
     /* If the premium account is expired we'll simply accept it as a free account. */
     String expire =
         br.getRegex(
                 "Reverts To Free Account:[\t\n\r ]+</td>[\t\n\r ]+<td>[\t\n\r ]+(\\d{2}/\\d{2}/\\d{4} \\d{2}:\\d{2}:\\d{2})")
             .getMatch(0);
     if (expire == null) {
       /* More wide RegEx to be more language independant */
       expire =
           br.getRegex(">[\t\n\r ]*?(\\d{2}/\\d{2}/\\d{4} \\d{2}:\\d{2}:\\d{2})[\t\n\r ]*?<")
               .getMatch(0);
     }
     if (expire == null) {
       account.setValid(false);
       return ai;
     }
     long expire_milliseconds = 0;
     expire_milliseconds =
         TimeFormatter.getMilliSeconds(expire, "MM/dd/yyyy hh:mm:ss", Locale.ENGLISH);
     if ((expire_milliseconds - System.currentTimeMillis()) <= 0) {
       account.setType(AccountType.FREE);
       account.setMaxSimultanDownloads(account_FREE_MAXDOWNLOADS);
       /* All accounts get the same (IP-based) downloadlimits --> Simultan free account usage makes no sense! */
       account.setConcurrentUsePossible(false);
       MAXPREM.set(account_FREE_MAXDOWNLOADS);
       ai.setStatus("Registered (free) user");
     } else {
       ai.setValidUntil(expire_milliseconds);
       account.setType(AccountType.PREMIUM);
       account.setMaxSimultanDownloads(account_PREMIUM_MAXDOWNLOADS);
       MAXPREM.set(account_PREMIUM_MAXDOWNLOADS);
       ai.setStatus("Premium account");
     }
   }
   account.setValid(true);
   ai.setUnlimitedTraffic();
   return ai;
 }
 @BeforeClass
 public static void verifyInitialCacheState() {
   resetContextCache();
   // Reset static counters in case tests are run multiple times in a test suite --
   // for example, via JUnit's @Suite.
   cacheHits.set(0);
   cacheMisses.set(0);
   assertContextCacheStatistics("BeforeClass", 0, cacheHits.get(), cacheMisses.get());
 }
Esempio n. 15
0
 private void login(Account account) throws Exception {
   this.setBrowserExclusive();
   br.setCookie("http://gigapeta.com", "lang", "us");
   br.setDebug(true);
   /*
    * Workaround for a serverside 502 error (date: 04.03.15). Accessing the wrong ('/dl/') link next line in the code will return a 404
    * error but we can login and download fine then.
    */
   br.getPage("http://gigapeta.com/dl/");
   final String auth_token = br.getRegex("name=\"auth_token\" value=\"([a-z0-9]+)\"").getMatch(0);
   final String lang = System.getProperty("user.language");
   if (auth_token == null) {
     if ("de".equalsIgnoreCase(lang)) {
       throw new PluginException(
           LinkStatus.ERROR_PREMIUM,
           "\r\nPlugin defekt, bitte den JDownloader Support kontaktieren!",
           PluginException.VALUE_ID_PREMIUM_DISABLE);
     } else {
       throw new PluginException(
           LinkStatus.ERROR_PREMIUM,
           "\r\nPlugin broken, please contact the JDownloader Support!",
           PluginException.VALUE_ID_PREMIUM_DISABLE);
     }
   }
   br.postPage(
       br.getURL(),
       "auth_login="******"&auth_passwd="
           + Encoding.urlEncode(account.getPass())
           + "&auth_token="
           + auth_token);
   if (br.getCookie("http://gigapeta.com/", "adv_sess") == null) {
     if ("de".equalsIgnoreCase(lang)) {
       throw new PluginException(
           LinkStatus.ERROR_PREMIUM,
           "\r\nUngültiger Benutzername oder ungültiges Passwort!\r\nDu bist dir sicher, dass dein eingegebener Benutzername und Passwort stimmen? Versuche folgendes:\r\n1. Falls dein Passwort Sonderzeichen enthält, ändere es (entferne diese) und versuche es erneut!\r\n2. Gib deine Zugangsdaten per Hand (ohne kopieren/einfügen) ein.",
           PluginException.VALUE_ID_PREMIUM_DISABLE);
     } else {
       throw new PluginException(
           LinkStatus.ERROR_PREMIUM,
           "\r\nInvalid username/password!\r\nYou're sure that the username and password you entered are correct? Some hints:\r\n1. If your password contains special characters, change it (remove them) and try again!\r\n2. Type in your username/password by hand without copy & paste.",
           PluginException.VALUE_ID_PREMIUM_DISABLE);
     }
   }
   if (br.containsHTML("You have <b>basic</b> account")) {
     nopremium = true;
     simultanpremium.set(1);
   } else if (br.getRegex("You have <b>([^<>\"]*?)</b> account till").getMatch(0) != null) {
     simultanpremium.set(-1);
   } else {
     logger.warning("Unknown accounttype, disabling it...");
     throw new PluginException(LinkStatus.ERROR_PREMIUM, PluginException.VALUE_ID_PREMIUM_DISABLE);
   }
 }
Esempio n. 16
0
  public void resetScore() {
    /*
     * score.set 与char2type.set这两个方法,虽然没有以原子的方式执行完成,但是
    却不影响整个类的安全性,因为这两个方法没有相互依赖,只需保证单个方法以原子的方式执行即可,
    这个情况与 java并发编程中的因式分解那个例子不同,
     */
    score.set(0);
    char2type.set(-1);

    setScore();
  }
Esempio n. 17
0
  /** {@inheritDoc} */
  @Override()
  public void finalizeBackend() {
    // Deregister as a change listener.
    cfg.removeLocalDBChangeListener(this);

    // Deregister our base DNs.
    for (DN dn : rootContainer.getBaseDNs()) {
      try {
        DirectoryServer.deregisterBaseDN(dn);
      } catch (Exception e) {
        if (debugEnabled()) {
          TRACER.debugCaught(DebugLogLevel.ERROR, e);
        }
      }
    }

    DirectoryServer.deregisterMonitorProvider(rootContainerMonitor);
    DirectoryServer.deregisterMonitorProvider(diskMonitor);

    // We presume the server will prevent more operations coming into this
    // backend, but there may be existing operations already in the
    // backend. We need to wait for them to finish.
    waitUntilQuiescent();

    // Close the database.
    try {
      rootContainer.close();
      rootContainer = null;
    } catch (DatabaseException e) {
      if (debugEnabled()) {
        TRACER.debugCaught(DebugLogLevel.ERROR, e);
      }
      Message message = ERR_JEB_DATABASE_EXCEPTION.get(e.getMessage());
      logError(message);
    }

    // Checksum this db environment and register its offline state id/checksum.
    DirectoryServer.registerOfflineBackendStateID(this.getBackendID(), checksumDbEnv());

    // Deregister the alert generator.
    DirectoryServer.deregisterAlertGenerator(this);

    // Make sure the thread counts are zero for next initialization.
    threadTotalCount.set(0);
    threadWriteCount.set(0);

    // Log an informational message.
    Message message = NOTE_BACKEND_OFFLINE.get(cfg.getBackendId());
    logError(message);
  }
Esempio n. 18
0
  /** takes a line of gcode and returns that gcode with a line number and checksum */
  public String applyNandChecksum(String gcode) {
    // RepRap Syntax: N<linenumber> <cmd> *<chksum>\n

    if (gcode.contains("M110")) lineNumber.set(-1);

    Matcher lineNumberMatcher = gcodeLineNumberPattern.matcher(gcode);
    if (lineNumberMatcher
        .matches()) { // reset our line number to the specified one. this is usually a m110 line #
      // reset
      lineNumber.set(Integer.parseInt(lineNumberMatcher.group(1)));
    } else { // only add a line number if it is not already specified
      gcode = "N" + lineNumber.incrementAndGet() + ' ' + gcode + ' ';
    }
    return applyChecksum(gcode);
  }
 /**
  * Tries to grow array to accommodate at least one more element (but normally expand by about
  * 50%), giving up (allowing retry) on contention (which we expect to be rare). Call only while
  * holding lock.
  *
  * @param array the heap array
  * @param oldCap the length of the array
  */
 private void tryGrow(Object[] array, int oldCap) {
   lock.unlock(); // must release and then re-acquire main lock
   Object[] newArray = null;
   if (allocationSpinLock.get() == 0 && allocationSpinLock.compareAndSet(0, 1)) {
     try {
       int newCap =
           oldCap
               + ((oldCap < 64)
                   ? (oldCap + 2)
                   : // grow faster if small
                   (oldCap >> 1));
       if (newCap - MAX_ARRAY_SIZE > 0) { // possible overflow
         int minCap = oldCap + 1;
         if (minCap < 0 || minCap > MAX_ARRAY_SIZE) throw new OutOfMemoryError();
         newCap = MAX_ARRAY_SIZE;
       }
       if (newCap > oldCap && deque == array) newArray = new Object[newCap];
     } finally {
       allocationSpinLock.set(0);
     }
   }
   if (newArray == null) // back off if another thread is allocating
   Thread.yield();
   lock.lock();
   if (newArray != null && deque == array) {
     deque = newArray;
     System.arraycopy(array, 0, newArray, 0, oldCap);
   }
 }
 private void triggerSnapshotIfRequired(
     String type, Object aggregateIdentifier, final AtomicInteger eventCount) {
   if (eventCount.get() > trigger) {
     snapshotter.scheduleSnapshot(type, aggregateIdentifier);
     eventCount.set(1);
   }
 }
Esempio n. 21
0
 @Override
 public boolean commit() {
   try {
     if (!writeSet.isEmpty()) {
       int v = status.get();
       int s = v & STATUS_MASK;
       if (s == TX_ACTIVE && status.compareAndSet(v, v + (TX_COMMITTING - TX_ACTIVE))) {
         long newClock = clock.incrementAndGet();
         if (newClock != startTime.get() + 1 && !readSet.validate(this, id)) {
           rollback0();
           return false;
         }
         // Write values and release locks
         writeSet.commit(newClock);
         status.set(v + (TX_COMMITTED - TX_ACTIVE));
       } else {
         // We have been killed: wait for our locks to have been released
         while (s != TX_ABORTED) s = status.get() & STATUS_MASK;
         return false;
       }
     } else {
       // No need to set status to COMMITTED (we cannot be killed with an empty write set)
     }
     attempts = 0;
     return true;
   } finally {
     if (irrevocableState) {
       irrevocableState = false;
       irrevocableAccessLock.writeLock().unlock();
     } else {
       irrevocableAccessLock.readLock().unlock();
     }
   }
 }
Esempio n. 22
0
  @Override
  protected void doSetUp() throws Exception {
    m_baseMetaChangeCount.set(0);
    defineComponent(
        EventHandler.class, "BaseMetaChangedEventHandler", TestBaseMetaChangedEventHandler.class);
    defineComponent(
        EventHandler.class,
        "MetaServerListChangedEventHandler",
        TestMetaServerListChangedEventHandler.class);

    LeaderInitEventHandler leaderInitEventHandler =
        (LeaderInitEventHandler) lookup(EventHandler.class, "LeaderInitEventHandler");
    leaderInitEventHandler.setMetaService(m_metaService);
    leaderInitEventHandler.setMetaServerAssignmentHolder(m_metaServerAssignmentHolder);
    leaderInitEventHandler.setMetaHolder(m_metaHolder);
    leaderInitEventHandler.setBrokerAssignmentHolder(m_brokerAssignmentHolder);

    when(m_metaService.getMetaEntity()).thenReturn(TestHelper.loadLocalMeta(this));

    m_curator
        .setData()
        .forPath(ZKPathUtils.getBaseMetaVersionZkPath(), ZKSerializeUtils.serialize(1L));

    leaderInitEventHandler.initialize();
    m_eventBus = lookup(EventBus.class);
  }
 private int computeSize() {
   synchronized (handles) {
     int size = handles.size();
     currentSize.set(size);
     return size;
   }
 }
  /**
   * Removes the specified element from this set if it is present. More formally, removes an element
   * {@code e} such that <tt>(o==null&nbsp;?&nbsp;e==null&nbsp;:&nbsp;o.equals(e))</tt>, if this set
   * contains such an element. Returns {@code true} if this set contained the element (or
   * equivalently, if this set changed as a result of the call). (This set will not contain the
   * element once the call returns.)
   *
   * <p>The {@code writeLock} will be locked throughout the entire operation.
   *
   * @param elem element to be removed from this set, if present
   * @return {@code true} if this set contained the specified element
   */
  public synchronized boolean remove(E elem) {
    final boolean retValue;
    int localLeftRight = leftRight.get();
    // Do the add() in the first Tree, opposite to the one currently
    // being used by the Read operations. No need to wait.
    if (localLeftRight == READS_ON_LEFT) {
      retValue = rightTree.remove(elem);
    } else {
      retValue = leftTree.remove(elem);
    }
    // Optimization that only works for Sets
    if (!retValue) return false;

    // Toggle leftRight and wait for currently running Readers
    leftRight.set(-localLeftRight);
    toggleVersionAndScan();

    if (-localLeftRight == READS_ON_LEFT) {
      rightTree.remove(elem);
    } else {
      leftTree.remove(elem);
    }

    return retValue;
  }
  @Test
  public void shouldEvalScriptWithMapBindingsAndLanguageThenConsume() throws Exception {
    final GremlinExecutor gremlinExecutor =
        GremlinExecutor.build()
            .addEngineSettings(
                "nashorn",
                Collections.emptyList(),
                Collections.emptyList(),
                Collections.emptyList(),
                Collections.emptyMap())
            .create();
    final Map<String, Object> b = new HashMap<>();
    b.put("x", 1);

    final CountDownLatch latch = new CountDownLatch(1);
    final AtomicInteger result = new AtomicInteger(0);
    assertEquals(
        2.0,
        gremlinExecutor
            .eval(
                "1+x",
                "nashorn",
                b,
                r -> {
                  result.set(((Double) r).intValue() * 2);
                  latch.countDown();
                })
            .get());

    latch.await();
    assertEquals(4, result.get());
    gremlinExecutor.close();
  }
Esempio n. 26
0
 protected void queueCommand(Command cmd) {
   commands.add(cmd);
   log("MASTER: Queuing command, and starting worker - " + cmd.getClass().getSimpleName());
   latch.countDown();
   waitForCommandToComplete();
   threadState.set(WAITING);
 }
Esempio n. 27
0
 @Override
 public void setEventSeqNum(int newSeqNum) {
   if (eventSequence.get() != newSeqNum) {
     eventSequence.set(newSeqNum);
     hasUpdate = true;
   }
 }
Esempio n. 28
0
 public void open() throws Exception {
   if (!file.isOpen()) {
     file.open();
   }
   size.set((int) file.size());
   file.position(0);
 }
Esempio n. 29
0
 public int getNextQueryNumber() {
   synchronized (queryCounter) {
     int i = queryCounter.intValue();
     queryCounter.set(i + 1);
     return i;
   }
 }
Esempio n. 30
0
  @Test
  public void testMapping() {
    List<String> input = Arrays.asList("Capital", "lower", "Foo", "bar");
    Collector<String, ?, Map<Boolean, Optional<Integer>>> collector =
        MoreCollectors.partitioningBy(
            str -> Character.isUpperCase(str.charAt(0)),
            MoreCollectors.mapping(String::length, MoreCollectors.first()));
    checkShortCircuitCollector(
        "mapping", new BooleanMap<>(Optional.of(7), Optional.of(5)), 2, input::stream, collector);
    Collector<String, ?, Map<Boolean, Optional<Integer>>> collectorLast =
        MoreCollectors.partitioningBy(
            str -> Character.isUpperCase(str.charAt(0)),
            MoreCollectors.mapping(String::length, MoreCollectors.last()));
    checkCollector(
        "last", new BooleanMap<>(Optional.of(3), Optional.of(3)), input::stream, collectorLast);

    input = Arrays.asList("Abc", "Bac", "Aac", "Abv", "Bbc", "Bgd", "Atc", "Bpv");
    Map<Character, List<String>> expected =
        EntryStream.of('A', Arrays.asList("Abc", "Aac"), 'B', Arrays.asList("Bac", "Bbc")).toMap();
    AtomicInteger cnt = new AtomicInteger();
    Collector<String, ?, Map<Character, List<String>>> groupMap =
        Collectors.groupingBy(
            s -> s.charAt(0),
            MoreCollectors.mapping(
                x -> {
                  cnt.incrementAndGet();
                  return x;
                },
                MoreCollectors.head(2)));
    checkCollector("groupMap", expected, input::stream, groupMap);
    cnt.set(0);
    assertEquals(expected, input.stream().collect(groupMap));
    assertEquals(4, cnt.get());
  }