RoutingProfilesCollection.java

/*  This file is part of Openrouteservice.
 *
 *  Openrouteservice is free software; you can redistribute it and/or modify it under the terms of the
 *  GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1
 *  of the License, or (at your option) any later version.

 *  This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Lesser General Public License for more details.

 *  You should have received a copy of the GNU Lesser General Public License along with this library;
 *  if not, see <https://www.gnu.org/licenses/>.
 */
package org.heigit.ors.routing;

import org.apache.log4j.Logger;
import org.heigit.ors.util.RuntimeUtility;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class RoutingProfilesCollection {
    private final HashMap<Integer, RoutingProfile> routeProfiles;
    private final ArrayList<RoutingProfile> uniqueProfiles;

    public RoutingProfilesCollection() {
        routeProfiles = new HashMap<>();
        uniqueProfiles = new ArrayList<>();
    }

    public void destroy() {
        for (RoutingProfile rp : uniqueProfiles) {
            rp.close();
        }
        routeProfiles.clear();
    }

    public List<RoutingProfile> getUniqueProfiles() {
        return uniqueProfiles;
    }

    public int size() {
        return uniqueProfiles.size();
    }

    public void clear() {
        routeProfiles.clear();
        uniqueProfiles.clear();
    }

    public boolean add(RoutingProfile rp) {
        boolean result = true;
        synchronized (uniqueProfiles) {
            uniqueProfiles.add(rp);
            Integer[] routePrefs = rp.getPreferences();
            if (routePrefs != null) {
                for (int j = 0; j < routePrefs.length; j++) {
                    if (!add(routePrefs[j], rp, false))
                        result = false;
                }
            }
        }
        return result;
    }

    public boolean add(int routePref, RoutingProfile rp, boolean isUnique) {
        boolean res = false;

        synchronized (routeProfiles) {
            int key = getRoutePreferenceKey(routePref, rp.isCHEnabled());

            if (!routeProfiles.containsKey(key)) {
                routeProfiles.put(key, rp);
                if (isUnique)
                    uniqueProfiles.add(rp);

                res = true;
            }

            if (rp.isCHEnabled()) {
                //  add the same profile but with dynamic weights
                key = getRoutePreferenceKey(routePref, false);

                if (!routeProfiles.containsKey(key)) {
                    routeProfiles.put(key, rp);
                    if (isUnique)
                        uniqueProfiles.add(rp);

                    res = true;
                }
            }
        }

        return res;
    }

    public List<RoutingProfile> getCarProfiles() {
        ArrayList<RoutingProfile> result = new ArrayList<>();
        for (RoutingProfile rp : routeProfiles.values()) {
            if (rp.hasCarPreferences())
                result.add(rp);
        }
        return result;
    }

    public RoutingProfile getRouteProfile(int routePref, boolean chEnabled) {
        int routePrefKey = getRoutePreferenceKey(routePref, chEnabled);
        //Fall back to non-CH version if CH routing profile does not exist
        if (!routeProfiles.containsKey(routePrefKey)) {
            routePrefKey = getRoutePreferenceKey(routePref, false);
            if (!routeProfiles.containsKey(routePrefKey))
                return null;
        }
        return routeProfiles.get(routePrefKey);
    }

    /**
     * Check if the CH graph of the specified profile has been built.
     *
     * @param routePref The chosen routing profile
     */

    public boolean isCHProfileAvailable(int routePref) {
        int routePrefKey = getRoutePreferenceKey(routePref, true);
        return routeProfiles.containsKey(routePrefKey);
    }

    public RoutingProfile getRouteProfile(int routePref) {
        return getRouteProfileByKey(getRoutePreferenceKey(routePref, false));
    }

    private RoutingProfile getRouteProfileByKey(int routePrefKey) {
        return routeProfiles.getOrDefault(routePrefKey, null);
    }

    private int getRoutePreferenceKey(int routePref, boolean chEnabled) {
        int key = routePref;
        if (chEnabled)
            key += 100;
        return key;
    }

    public void printStatistics(Logger logger) {
        logger.info("====> Memory usage by profiles:");
        long totalUsedMemory = Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
        long totalProfilesMemory = 0;

        int i = 0;
        for (RoutingProfile profile : getUniqueProfiles()) {
            i++;
            long profileMemory = profile.getMemoryUsage();
            totalProfilesMemory += profileMemory;
            logger.info("[%d] %s (%.1f%%)".formatted(i, RuntimeUtility.getMemorySize(profileMemory), ((double) profileMemory / totalUsedMemory) * 100));
        }
        logger.info("Total: %s (%.1f%%)".formatted(RuntimeUtility.getMemorySize(totalProfilesMemory), ((double) totalProfilesMemory / totalUsedMemory) * 100));
        logger.info("========================================================================");
    }
}