com.intellij.psi.statistics.impl.StatisticsManagerImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.intellij.psi.statistics.impl.StatisticsManagerImpl.java

Source

/*
 * Copyright 2000-2009 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.intellij.psi.statistics.impl;

import com.intellij.CommonBundle;
import com.intellij.ide.IdeBundle;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Disposer;
import com.intellij.psi.statistics.StatisticsInfo;
import com.intellij.psi.statistics.StatisticsManager;
import com.intellij.reference.SoftReference;
import com.intellij.util.NotNullFunction;
import com.intellij.util.ScrambledInputStream;
import com.intellij.util.ScrambledOutputStream;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;

import java.io.*;
import java.util.Arrays;
import java.util.HashSet;

public class StatisticsManagerImpl extends StatisticsManager {
    private static final int UNIT_COUNT = 997;
    private static final Object LOCK = new Object();

    @NonNls
    private static final String STORE_PATH = PathManager.getSystemPath() + File.separator + "stat";

    private final SoftReference[] myUnits = new SoftReference[UNIT_COUNT];
    private final HashSet<StatisticsUnit> myModifiedUnits = new HashSet<StatisticsUnit>();
    private boolean myTestingStatistics;

    public int getUseCount(@NotNull final StatisticsInfo info) {
        if (info == StatisticsInfo.EMPTY)
            return 0;

        int useCount = 0;

        for (StatisticsInfo conjunct : info.getConjuncts()) {
            useCount = Math.max(doGetUseCount(conjunct), useCount);
        }

        return useCount;
    }

    private int doGetUseCount(StatisticsInfo info) {
        String key1 = info.getContext();
        int unitNumber = getUnitNumber(key1);
        synchronized (LOCK) {
            StatisticsUnit unit = getUnit(unitNumber);
            return unit.getData(key1, info.getValue());
        }
    }

    @Override
    public int getLastUseRecency(@NotNull StatisticsInfo info) {
        if (info == StatisticsInfo.EMPTY)
            return 0;

        int recency = Integer.MAX_VALUE;
        for (StatisticsInfo conjunct : info.getConjuncts()) {
            recency = Math.min(doGetRecency(conjunct), recency);
        }
        return recency;
    }

    private int doGetRecency(StatisticsInfo info) {
        String key1 = info.getContext();
        int unitNumber = getUnitNumber(key1);
        synchronized (LOCK) {
            StatisticsUnit unit = getUnit(unitNumber);
            return unit.getRecency(key1, info.getValue());
        }
    }

    public void incUseCount(@NotNull final StatisticsInfo info) {
        if (info == StatisticsInfo.EMPTY)
            return;
        if (ApplicationManager.getApplication().isUnitTestMode() && !myTestingStatistics) {
            return;
        }

        ApplicationManager.getApplication().assertIsDispatchThread();

        for (StatisticsInfo conjunct : info.getConjuncts()) {
            doIncUseCount(conjunct);
        }
    }

    private void doIncUseCount(StatisticsInfo info) {
        final String key1 = info.getContext();
        int unitNumber = getUnitNumber(key1);
        synchronized (LOCK) {
            StatisticsUnit unit = getUnit(unitNumber);
            unit.incData(key1, info.getValue());
            myModifiedUnits.add(unit);
        }
    }

    public StatisticsInfo[] getAllValues(final String context) {
        final String[] strings;
        synchronized (LOCK) {
            strings = getUnit(getUnitNumber(context)).getKeys2(context);
        }
        return ContainerUtil.map2Array(strings, StatisticsInfo.class,
                new NotNullFunction<String, StatisticsInfo>() {
                    @NotNull
                    public StatisticsInfo fun(final String s) {
                        return new StatisticsInfo(context, s);
                    }
                });
    }

    public void save() {
        synchronized (LOCK) {
            if (!ApplicationManager.getApplication().isUnitTestMode()) {
                ApplicationManager.getApplication().assertIsDispatchThread();
                for (StatisticsUnit unit : myModifiedUnits) {
                    saveUnit(unit.getNumber());
                }
            }
            myModifiedUnits.clear();
        }
    }

    private StatisticsUnit getUnit(int unitNumber) {
        SoftReference ref = myUnits[unitNumber];
        if (ref != null) {
            StatisticsUnit unit = (StatisticsUnit) ref.get();
            if (unit != null)
                return unit;
        }
        StatisticsUnit unit = loadUnit(unitNumber);
        if (unit == null) {
            unit = new StatisticsUnit(unitNumber);
        }
        myUnits[unitNumber] = new SoftReference<StatisticsUnit>(unit);
        return unit;
    }

    private static StatisticsUnit loadUnit(int unitNumber) {
        StatisticsUnit unit = new StatisticsUnit(unitNumber);
        if (!ApplicationManager.getApplication().isUnitTestMode()) {
            String path = getPathToUnit(unitNumber);
            try {
                InputStream in = new BufferedInputStream(new FileInputStream(path));
                in = new ScrambledInputStream(in);
                try {
                    unit.read(in);
                } finally {
                    in.close();
                }
            } catch (IOException e) {
            } catch (WrongFormatException e) {
            }
        }
        return unit;
    }

    private void saveUnit(int unitNumber) {
        if (!createStoreFolder())
            return;
        StatisticsUnit unit = getUnit(unitNumber);
        String path = getPathToUnit(unitNumber);
        try {
            OutputStream out = new BufferedOutputStream(new FileOutputStream(path));
            out = new ScrambledOutputStream(out);
            try {
                unit.write(out);
            } finally {
                out.close();
            }
        } catch (IOException e) {
            Messages.showMessageDialog(IdeBundle.message("error.saving.statistics", e.getLocalizedMessage()),
                    CommonBundle.getErrorTitle(), Messages.getErrorIcon());
        }
    }

    private static int getUnitNumber(String key1) {
        return Math.abs(key1.hashCode()) % UNIT_COUNT;
    }

    private static boolean createStoreFolder() {
        File homeFile = new File(STORE_PATH);
        if (!homeFile.exists()) {
            if (!homeFile.mkdirs()) {
                Messages.showMessageDialog(
                        IdeBundle.message("error.saving.statistic.failed.to.create.folder", STORE_PATH),
                        CommonBundle.getErrorTitle(), Messages.getErrorIcon());
                return false;
            }
        }
        return true;
    }

    @SuppressWarnings({ "HardCodedStringLiteral" })
    private static String getPathToUnit(int unitNumber) {
        return STORE_PATH + File.separator + "unit." + unitNumber;
    }

    @TestOnly
    public void enableStatistics(@NotNull Disposable parentDisposable) {
        myTestingStatistics = true;
        Disposer.register(parentDisposable, new Disposable() {
            @Override
            public void dispose() {
                synchronized (LOCK) {
                    Arrays.fill(myUnits, null);
                }
                myTestingStatistics = false;
            }
        });
    }

}