private boolean handleGCPauseForGet()

in evcache-core/src/main/java/com/netflix/evcache/operation/EVCacheOperationFuture.java [162:221]


    private boolean handleGCPauseForGet(long duration, TimeUnit units, boolean throwException, boolean hasZF) throws InterruptedException, ExecutionException {
        boolean status;
        boolean gcPause = false;
        final RuntimeMXBean runtimeBean = ManagementFactory.getRuntimeMXBean();
        final long vmStartTime = runtimeBean.getStartTime();
        final List<GarbageCollectorMXBean> gcMXBeans = ManagementFactory.getGarbageCollectorMXBeans();
        for (GarbageCollectorMXBean gcMXBean : gcMXBeans) {
            if (gcMXBean instanceof com.sun.management.GarbageCollectorMXBean) {
                final GcInfo lastGcInfo = ((com.sun.management.GarbageCollectorMXBean) gcMXBean).getLastGcInfo();

                // If no GCs, there was no pause due to GC.
                if (lastGcInfo == null) {
                    continue;
                }

                final long gcStartTime = lastGcInfo.getStartTime() + vmStartTime;
                if (gcStartTime > start) {
                    gcPause = true;
                    final long gcDuration = lastGcInfo.getDuration();
                    final long pauseDuration = System.currentTimeMillis() - gcStartTime;
                    if (log.isDebugEnabled()) {
                        log.debug("Event Start Time = " + start + "; Last GC Start Time = " + gcStartTime + "; " + (gcStartTime - start) + " msec ago.\n"
                                    + "\nTotal pause duration due for this event = " + pauseDuration + " msec.\nTotal GC duration = " + gcDuration + " msec.");
                    }
                    break;
                }
            }
        }
        if (!gcPause && log.isDebugEnabled()) {
            log.debug("Total pause duration due to NON-GC event = " + (System.currentTimeMillis() - start) + " msec.");
        }
        // redo the same op once more since there was a chance of gc pause
        status = latch.await(duration, units);

        if (log.isDebugEnabled()) log.debug("re-await status : " + status);
        String statusString = EVCacheMetricsFactory.SUCCESS;
        final long pauseDuration = System.currentTimeMillis() - start;
        if (op != null && !status) {
            // whenever timeout occurs, continuous timeout counter will increase by 1.
            MemcachedConnection.opTimedOut(op);
            op.timeOut();
            ExecutionException t = null;
            if(throwException && !hasZF) {
                if (op.isTimedOut()) { t = new ExecutionException(new CheckedOperationTimeoutException("Checked Operation timed out.", op)); statusString = EVCacheMetricsFactory.CHECKED_OP_TIMEOUT; }
                else if (op.isCancelled()  && throwException) { t = new ExecutionException(new CancellationException("Cancelled"));statusString = EVCacheMetricsFactory.CANCELLED; }
                else if (op.hasErrored() ) { t = new ExecutionException(op.getException());statusString = EVCacheMetricsFactory.ERROR; }
            }

            if(t != null) throw t; //finally throw the exception if needed
        }

        final List<Tag> tagList = new ArrayList<Tag>(client.getTagList().size() + 4);
        tagList.addAll(client.getTagList());
        tagList.add(new BasicTag(EVCacheMetricsFactory.CALL_TAG, EVCacheMetricsFactory.GET_OPERATION));
        tagList.add(new BasicTag(EVCacheMetricsFactory.PAUSE_REASON, gcPause ? EVCacheMetricsFactory.GC:EVCacheMetricsFactory.SCHEDULE));
        tagList.add(new BasicTag(EVCacheMetricsFactory.FETCH_AFTER_PAUSE, status ? EVCacheMetricsFactory.YES:EVCacheMetricsFactory.NO));
        tagList.add(new BasicTag(EVCacheMetricsFactory.OPERATION_STATUS, statusString));
        EVCacheMetricsFactory.getInstance().getPercentileTimer(EVCacheMetricsFactory.INTERNAL_PAUSE, tagList, Duration.ofMillis(EVCacheConfig.getInstance().getPropertyRepository().get(getApp() + ".max.write.duration.metric", Integer.class).orElseGet("evcache.max.write.duration.metric").orElse(50).get().intValue())).record(pauseDuration, TimeUnit.MILLISECONDS);
        return status;
    }