blob: 53dc03c97bd17a1d4e9b7936b56ef08133511204 [file] [log] [blame]
/*
* 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);
}
}
}