| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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 org.apache.mnemonic; |
| |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.commons.lang3.tuple.Pair; |
| import org.apache.mnemonic.service.computing.GeneralComputingService; |
| import org.apache.mnemonic.service.memory.NonVolatileMemoryAllocatorService; |
| import org.apache.mnemonic.service.memory.VolatileMemoryAllocatorService; |
| |
| import java.io.File; |
| import java.lang.reflect.Field; |
| import java.nio.Buffer; |
| import java.nio.ByteBuffer; |
| import java.text.SimpleDateFormat; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Date; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Random; |
| import java.util.ServiceLoader; |
| import java.util.UUID; |
| import java.lang.reflect.InvocationTargetException; |
| |
| /** |
| * <p> |
| * Utilities for project. |
| * </p> |
| * |
| */ |
| @SuppressWarnings("restriction") |
| public class Utils { |
| |
| public static final String ANSI_RESET = "\u001B[0m"; |
| public static final String ANSI_BLACK = "\u001B[30m"; |
| public static final String ANSI_RED = "\u001B[31m"; |
| public static final String ANSI_GREEN = "\u001B[32m"; |
| public static final String ANSI_YELLOW = "\u001B[33m"; |
| public static final String ANSI_BLUE = "\u001B[34m"; |
| public static final String ANSI_PURPLE = "\u001B[35m"; |
| public static final String ANSI_CYAN = "\u001B[36m"; |
| public static final String ANSI_WHITE = "\u001B[37m"; |
| |
| @SuppressWarnings({"restriction", "UseOfSunClasses"}) |
| private static sun.misc.Unsafe m_unsafe = null; |
| |
| private static ServiceLoader<VolatileMemoryAllocatorService> m_vmasvcloader = null; |
| private static ServiceLoader<NonVolatileMemoryAllocatorService> m_nvmasvcloader = null; |
| private static ServiceLoader<GeneralComputingService> m_gcompsvcloader = null; |
| |
| /** |
| * retrieve a volatile memory allocator service |
| * |
| * @param id |
| * specify a name of allocator to retrieve |
| * |
| * @return the volatile memory allocator service instance |
| */ |
| public static VolatileMemoryAllocatorService getVolatileMemoryAllocatorService(String id) { |
| return getVolatileMemoryAllocatorService(id, true); |
| } |
| |
| /** |
| * retrieve a volatile memory allocator service |
| * |
| * @param id |
| * specify a name of allocator to retrieve |
| * |
| * @param allownvmsvc |
| * specify whether allow to treat non-volatile memory allocator as |
| * volatile one during searching |
| * |
| * @return the volatile memory allocator service instance |
| */ |
| public static VolatileMemoryAllocatorService getVolatileMemoryAllocatorService(String id, boolean allownvmsvc) { |
| VolatileMemoryAllocatorService ret = null; |
| if (null == m_vmasvcloader) { |
| m_vmasvcloader = ServiceLoader.load(VolatileMemoryAllocatorService.class); |
| } |
| Iterator<VolatileMemoryAllocatorService> svcit = m_vmasvcloader.iterator(); |
| VolatileMemoryAllocatorService svc = null; |
| while (null == ret && svcit.hasNext()) { |
| svc = svcit.next(); |
| if (svc.getServiceId().equals(id)) { |
| ret = svc; |
| } |
| } |
| if (null == ret && allownvmsvc) { |
| ret = getNonVolatileMemoryAllocatorService(id); |
| } |
| assert null != ret : "VolatileMemoryAllocatorService \'" + id + "\' not found!"; |
| return ret; |
| } |
| |
| /** |
| * retrieve a non-volatile memory allocator service |
| * |
| * @param id |
| * specify a name of allocator to retrieve |
| * |
| * @return the non-volatile memory allocator service instance |
| */ |
| public static synchronized NonVolatileMemoryAllocatorService getNonVolatileMemoryAllocatorService(String id) { |
| NonVolatileMemoryAllocatorService ret = null; |
| if (null == m_nvmasvcloader) { |
| m_nvmasvcloader = ServiceLoader.load(NonVolatileMemoryAllocatorService.class); |
| } |
| Iterator<NonVolatileMemoryAllocatorService> svcit = m_nvmasvcloader.iterator(); |
| NonVolatileMemoryAllocatorService svc = null; |
| while (svcit.hasNext()) { |
| svc = svcit.next(); |
| if (svc.getServiceId().equals(id)) { |
| ret = svc; |
| break; |
| } |
| } |
| assert null != ret : "NonVolatileMemoryAllocatorService \'" + id + "\' not found!"; |
| return ret; |
| } |
| |
| /** |
| * retrieve a durable general computing service |
| * |
| * @param id |
| * specify a name of general computing to retrieve |
| * |
| * @return the durable general computing service instance |
| */ |
| public static synchronized GeneralComputingService getGeneralComputingService(String id) { |
| GeneralComputingService ret = null; |
| if (null == m_gcompsvcloader) { |
| m_gcompsvcloader = ServiceLoader.load(GeneralComputingService.class); |
| } |
| Iterator<GeneralComputingService> svcit = m_gcompsvcloader.iterator(); |
| GeneralComputingService svc = null; |
| while (svcit.hasNext()) { |
| svc = svcit.next(); |
| if (svc.getServiceId().equals(id)) { |
| ret = svc; |
| break; |
| } |
| } |
| assert null != ret : "GeneralComputingService \'" + id + "\' not found!"; |
| return ret; |
| } |
| |
| /** |
| * Generates a unique name that contains current timestamp. |
| * |
| * @param format |
| * the template that is used to generate unique name. |
| * |
| * @return unique path name. |
| */ |
| public static String genUniquePathname(String format) { |
| String ret = null; |
| if (null != format && !format.isEmpty()) { |
| ret = String.format(format, (new SimpleDateFormat("ddMMyy-hhmmss.SSS").format(new Date()))); |
| } |
| return ret; |
| } |
| |
| /** |
| * retrieve the usage of memory. |
| * |
| * @param timeout |
| * specify a timeout for this operation |
| * |
| * @return the size of memory has been occupied |
| */ |
| public static long getMemoryUse(long timeout) { |
| putOutTheGarbage(timeout); |
| long totalMemory = Runtime.getRuntime().totalMemory(); |
| putOutTheGarbage(timeout); |
| long freeMemory = Runtime.getRuntime().freeMemory(); |
| return (totalMemory - freeMemory); |
| } |
| |
| /** |
| * run garbage collections. |
| */ |
| private static void putOutTheGarbage(long timeout) { |
| collectGarbage(timeout); |
| collectGarbage(timeout); |
| } |
| |
| /** |
| * run a garbage collection. |
| * |
| * @param timeout |
| * specify a timeout for this operation |
| * |
| */ |
| public static void collectGarbage(long timeout) { |
| try { |
| System.gc(); |
| Thread.sleep(timeout); |
| System.runFinalization(); |
| Thread.sleep(timeout); |
| } catch (InterruptedException ex) { |
| ex.printStackTrace(); |
| } |
| } |
| |
| /** |
| * Retrieve an Unsafe object. |
| * |
| * @throws Exception |
| * Error when get Unsafe object from runtime |
| * |
| * @return an unsafe object |
| */ |
| @SuppressWarnings({"restriction", "UseOfSunClasses"}) |
| public static sun.misc.Unsafe getUnsafe() throws Exception { |
| if (null == m_unsafe) { |
| Field field = sun.misc.Unsafe.class.getDeclaredField("theUnsafe"); |
| field.setAccessible(true); |
| m_unsafe = (sun.misc.Unsafe) field.get(null); |
| } |
| return m_unsafe; |
| } |
| |
| /** |
| * resize a bytebuffer with a new instance |
| * |
| * @param buf |
| * specify a buf to resize |
| * |
| * @param size |
| * specify the size for resizing |
| * |
| * @return the resized bytebuffer instance |
| */ |
| public static ByteBuffer resizeByteBuffer(ByteBuffer buf, long size) { |
| ByteBuffer ret = ByteBuffer.allocateDirect((int) size); |
| if (ret != null) { |
| if (null != buf) { |
| ret.put(buf); |
| ret.flip(); |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| * create a new instance of Random using default fixed seed |
| * |
| * @return the instance of Random |
| */ |
| public static Random createRandom() { |
| return createRandom(0L); |
| } |
| |
| /** |
| * create a new instance of Random |
| * |
| * @param rgenseed |
| * specify a random seed |
| * |
| * @return the instance of Random |
| */ |
| public static Random createRandom(long rgenseed) { |
| Random ret = new Random(); |
| if (0L == rgenseed) { |
| rgenseed = System.currentTimeMillis(); |
| System.out.println("Random number generator seed is " + rgenseed); |
| } else { |
| System.out.println("Fixed Random number generator seed is " + rgenseed); |
| } |
| ret.setSeed(rgenseed); |
| return ret; |
| } |
| |
| /** |
| * generate a random string with fixed length |
| * |
| * @return the random string |
| */ |
| public static String genRandomString() { |
| return genRandomString(6); |
| } |
| |
| /** |
| * generate a random string |
| * |
| * @param len |
| * specify the length of this random string |
| * |
| * @return the random string |
| */ |
| public static String genRandomString(int len) { |
| return UUID.randomUUID().toString().replaceAll("-", "").toUpperCase().substring(0, len); |
| } |
| |
| /** |
| * assert the equality of two generic objects using compareTo() operator |
| * |
| * @param <T> |
| * the type of comparable objects |
| * |
| * @param actual |
| * specify a object to be compared |
| * |
| * @param expected |
| * specify a object to be expected |
| * |
| * @return true if equal according to compareTo() |
| */ |
| public static <T extends Comparable<T>> boolean assertComparison(T actual, T expected) { |
| boolean ret = false; |
| if ((expected == null) && (actual == null)) { |
| ret = true; |
| } else if (expected != null) { |
| ret = expected.compareTo(actual) == 0; |
| } |
| return ret; |
| } |
| |
| /** |
| * convert a long array to a initializer literal string. |
| * |
| * @param larr |
| * specify a long array to be converted |
| * |
| * @return a literal string represent the initializer |
| */ |
| public static String toInitLiteral(long[] larr) { |
| return Arrays.toString(larr).replaceAll("\\[", "{").replaceAll("\\]", "}"); |
| } |
| |
| /** |
| * convert a list of long array to a initializer literal string. |
| * |
| * @param llarr |
| * specify a list of long array to be converted |
| * |
| * @return a literal string represent the initializer |
| */ |
| public static String toInitLiteral(List<long[]> llarr) { |
| List<String> slist = new ArrayList<String>(); |
| for (long[] larr : llarr) { |
| slist.add(toInitLiteral(larr)); |
| } |
| return "{" + StringUtils.join(slist, ",") + "}"; |
| } |
| |
| /** |
| * retrieve a set of native field info from a list of object field info |
| * according to the field id info. it forms a value info stack for native code |
| * to use as one standardized parameter |
| * |
| * @param objstack |
| * a stack of object info retrieved from |
| * Durable.getNativeFieldInfo(), order matters |
| * |
| * @param fidinfostack |
| * a stack of field id in the form of (next_fid, next_level_fid) |
| * order follows objstack the last next_level_fid specifies the |
| * value's fid. the last item of next_fid could be null if there is |
| * no next node if it is null that means the last item is a object |
| * instead of node |
| * |
| * @return the stack of native field info |
| * |
| */ |
| public static List<long[]> getNativeParamForm(List<long[][]> objstack, long[][] fidinfostack) { |
| List<long[]> ret = null; |
| if (null == objstack || null == fidinfostack || fidinfostack.length != objstack.size()) { |
| throw new IllegalArgumentException("Not the same depth"); |
| } |
| ret = new ArrayList<long[]>(); |
| for (int idx = 0; idx < fidinfostack.length; ++idx) { |
| ret.add(genNativeStackItem(objstack.get(idx), fidinfostack[idx], idx == fidinfostack.length - 1)); |
| } |
| return ret; |
| } |
| |
| /** |
| * convert list form of native parameters to array form |
| * |
| * @param npf |
| * a list of native parameters |
| * |
| * @return the 2d array form of native parameter frame |
| */ |
| public static long[][] convertTo2DArrayForm(List<long[]> npf) { |
| long[][] ret = null; |
| if (null != npf && npf.size() > 0) { |
| ret = npf.toArray(new long[npf.size()][]); |
| } |
| return ret; |
| } |
| |
| /** |
| * generate native form of object stack parameter frame. |
| * |
| * @param objstack |
| * a stack of object info retrieved from |
| * Durable.getNativeFieldInfo(), order matters |
| * |
| * @param fidinfostack |
| * a stack of field id in the form of (next_fid, next_level_fid) |
| * order follows objstack the last next_level_fid specifies the |
| * value's fid. the last item of next_fid could be null if there is |
| * no next node if it is null that means the last item is a object |
| * instead of node |
| * |
| * @return the 2d array form of native parameter frame |
| * |
| * @see #getNativeParamForm(List, long[][]) |
| * |
| */ |
| public static long[][] genNativeParamForm(List<long[][]> objstack, long[][] fidinfostack) { |
| return convertTo2DArrayForm(getNativeParamForm(objstack, fidinfostack)); |
| } |
| |
| /** |
| * generate an item of native stack. |
| * |
| * @param oinfo |
| * a object field info |
| * |
| * @param fidinfo |
| * a pair of field id info |
| * |
| * @param allowfidnull |
| * allow the first field id is null |
| * |
| * @return the native item |
| */ |
| public static long[] genNativeStackItem(long[][] oinfo, long[] fidinfo, boolean allowfidnull) { |
| long[] ret = new long[4]; |
| long fid; |
| boolean found; |
| if (fidinfo.length != 2) { |
| throw new IllegalArgumentException("the length of field id array is not exactly 2"); |
| } |
| for (int idx = 0; idx < fidinfo.length; ++idx) { |
| ret[idx * 2] = -1L; |
| ret[idx * 2 + 1] = 0L; |
| fid = fidinfo[idx]; |
| if (fid <= 0) { |
| if (allowfidnull && 0 == idx) { |
| continue; |
| } else { |
| throw new IllegalArgumentException("the field id is not greater than 0"); |
| } |
| } |
| found = false; |
| for (long[] finfo : oinfo) { |
| if (finfo.length != 3) { |
| throw new IllegalArgumentException("the length of field array is not exactly 3"); |
| } |
| if (fid == finfo[0]) { |
| ret[idx * 2] = finfo[1]; |
| ret[idx * 2 + 1] = finfo[2]; |
| found = true; |
| } |
| } |
| if (!found) { |
| throw new IllegalArgumentException("field id not found"); |
| } |
| } |
| return ret; |
| } |
| |
| /** |
| * instantiate an array of entity factory proxy classes. |
| * |
| * @param proxyclses |
| * an array of entity factory proxy classes |
| * |
| * @return the array of instances |
| */ |
| public static EntityFactoryProxy[] instantiateEntityFactoryProxies(Class<?>[] proxyclses) { |
| List<EntityFactoryProxy> ret = new ArrayList<EntityFactoryProxy>(); |
| try { |
| for (Class<?> itm : proxyclses) { |
| if (EntityFactoryProxy.class.isAssignableFrom(itm)) { |
| ret.add((EntityFactoryProxy)itm.getDeclaredConstructor().newInstance()); |
| } else { |
| throw new ConfigurationException(String.format("%s is not EntityFactoryProxy", itm.getName())); |
| } |
| } |
| } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) { |
| throw new IllegalArgumentException("Failed to instantiate assigned EntityFactoryProxy classes.", e); |
| } |
| return ret.toArray(new EntityFactoryProxy[0]); |
| } |
| |
| /** |
| * shift durable parameters. |
| * |
| * @param gtypes |
| * an array of entity generic types |
| * |
| * @param factoryproxies |
| * an array of entity factory proxies |
| * |
| * @param len |
| * the length to shift from start |
| * |
| * @return the pair of shifted parameters. |
| */ |
| public static Pair<DurableType[], EntityFactoryProxy[]> shiftDurableParams( |
| DurableType[] gtypes, EntityFactoryProxy[] factoryproxies, int len) { |
| if (0 == len) { |
| return Pair.of(gtypes, factoryproxies); |
| } |
| DurableType[] ret_gtypes = {}; |
| EntityFactoryProxy[] ret_proxies = {}; |
| if (null != gtypes && gtypes.length > len) { |
| ret_gtypes = Arrays.copyOfRange(gtypes, len, gtypes.length); |
| } |
| if (null != factoryproxies && factoryproxies.length > len) { |
| ret_proxies = Arrays.copyOfRange(factoryproxies, len, factoryproxies.length); |
| } |
| return Pair.of(ret_gtypes, ret_proxies); |
| } |
| |
| public static void deleteFileOnly(String pathname) { |
| File f = new File(pathname); |
| if (f.isFile()) { |
| if (!f.delete()) { |
| throw new ConfigurationException(String.format("Failure to delete the file %s.", pathname)); |
| } |
| } |
| } |
| |
| /** |
| * get the address of an object |
| * |
| * @param unsafe |
| * an unsafe object |
| * @param o |
| * an object to retrieve its address |
| * |
| * @return |
| * the address of this object |
| */ |
| @SuppressWarnings({"restriction", "UseOfSunClasses"}) |
| public static long addressOf(sun.misc.Unsafe unsafe, Object o) { |
| Object[] array = new Object[] {o}; |
| |
| long baseOffset = unsafe.arrayBaseOffset(Object[].class); |
| int addressSize = unsafe.addressSize(); |
| long objectAddress; |
| switch (addressSize) { |
| case 4: |
| objectAddress = unsafe.getInt(array, baseOffset); |
| break; |
| case 8: |
| objectAddress = unsafe.getLong(array, baseOffset); |
| break; |
| default: |
| throw new Error("unsupported address size: " + addressSize); |
| } |
| return objectAddress; |
| } |
| |
| |
| |
| /** |
| * Gets the address value for the memory that backs a direct byte buffer. |
| * |
| * @param buffer |
| * A buffer to retrieve its address |
| * |
| * @return |
| * The system address for the buffers |
| */ |
| public static long getAddressFromDirectByteBuffer(ByteBuffer buffer) { |
| try { |
| Field addressField = Buffer.class.getDeclaredField("address"); |
| addressField.setAccessible(true); |
| return addressField.getLong(buffer); |
| } catch (Exception e) { |
| throw new RuntimeException("Unable to address field from ByteBuffer", e); |
| } |
| } |
| |
| } |