1 | /*
|
---|
2 | * Copyright (c) 2012 Jan Kotek
|
---|
3 | *
|
---|
4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
---|
5 | * you may not use this file except in compliance with the License.
|
---|
6 | * You may obtain a copy of the License at
|
---|
7 | *
|
---|
8 | * http://www.apache.org/licenses/LICENSE-2.0
|
---|
9 | *
|
---|
10 | * Unless required by applicable law or agreed to in writing, software
|
---|
11 | * distributed under the License is distributed on an "AS IS" BASIS,
|
---|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
13 | * See the License for the specific language governing permissions and
|
---|
14 | * limitations under the License.
|
---|
15 | */
|
---|
16 |
|
---|
17 | package org.mapdb;
|
---|
18 |
|
---|
19 | import java.io.*;
|
---|
20 | import java.nio.ByteBuffer;
|
---|
21 | import java.util.*;
|
---|
22 | import java.util.concurrent.atomic.AtomicLong;
|
---|
23 | import java.util.logging.Logger;
|
---|
24 |
|
---|
25 | /**
|
---|
26 | * Various IO related utilities
|
---|
27 | *
|
---|
28 | * @author Jan Kotek
|
---|
29 | * @author Nathan Sweet wrote long packer utils
|
---|
30 | */
|
---|
31 | @SuppressWarnings("unchecked")
|
---|
32 | final public class Utils {
|
---|
33 |
|
---|
34 | static final Logger LOG = Logger.getLogger("JDBM");
|
---|
35 |
|
---|
36 |
|
---|
37 | @SuppressWarnings("rawtypes")
|
---|
38 | public static final Comparator<Comparable> COMPARABLE_COMPARATOR = new Comparator<Comparable>() {
|
---|
39 | @Override
|
---|
40 | public int compare(Comparable o1, Comparable o2) {
|
---|
41 | return o1.compareTo(o2);
|
---|
42 | }
|
---|
43 | };
|
---|
44 |
|
---|
45 | @SuppressWarnings("rawtypes")
|
---|
46 | public static final Comparator<Comparable> COMPARABLE_COMPARATOR_WITH_NULLS = new Comparator<Comparable>() {
|
---|
47 | @Override
|
---|
48 | public int compare(Comparable o1, Comparable o2) {
|
---|
49 | return o1 == null && o2 != null ? -1 : (o1 != null && o2 == null ? 1 : o1.compareTo(o2));
|
---|
50 | }
|
---|
51 | };
|
---|
52 |
|
---|
53 |
|
---|
54 | public static final String EMPTY_STRING = "";
|
---|
55 | public static final String UTF8 = "UTF8";
|
---|
56 | public static Random RANDOM = new Random();
|
---|
57 |
|
---|
58 |
|
---|
59 | /**
|
---|
60 | * Pack non-negative long into output stream.
|
---|
61 | * It will occupy 1-10 bytes depending on value (lower values occupy smaller space)
|
---|
62 | *
|
---|
63 | * @param out DataOutput to put value into
|
---|
64 | * @param value to be serialized, must be non-negative
|
---|
65 | * @throws java.io.IOException
|
---|
66 | */
|
---|
67 | static public void packLong(DataOutput out, long value) throws IOException {
|
---|
68 |
|
---|
69 | if (value < 0) {
|
---|
70 | throw new IllegalArgumentException("negative value: keys=" + value);
|
---|
71 | }
|
---|
72 |
|
---|
73 | while ((value & ~0x7FL) != 0) {
|
---|
74 | out.write((((int) value & 0x7F) | 0x80));
|
---|
75 | value >>>= 7;
|
---|
76 | }
|
---|
77 | out.write((byte) value);
|
---|
78 | }
|
---|
79 |
|
---|
80 |
|
---|
81 | /**
|
---|
82 | * Unpack positive long value from the input stream.
|
---|
83 | *
|
---|
84 | * @param in The input stream.
|
---|
85 | * @return The long value.
|
---|
86 | * @throws java.io.IOException
|
---|
87 | */
|
---|
88 | static public long unpackLong(DataInput in) throws IOException {
|
---|
89 |
|
---|
90 | long result = 0;
|
---|
91 | for (int offset = 0; offset < 64; offset += 7) {
|
---|
92 | long b = in.readUnsignedByte();
|
---|
93 | result |= (b & 0x7F) << offset;
|
---|
94 | if ((b & 0x80) == 0) {
|
---|
95 | return result;
|
---|
96 | }
|
---|
97 | }
|
---|
98 | throw new Error("Malformed long.");
|
---|
99 | }
|
---|
100 |
|
---|
101 |
|
---|
102 | /**
|
---|
103 | * Pack non-negative long into output stream.
|
---|
104 | * It will occupy 1-5 bytes depending on value (lower values occupy smaller space)
|
---|
105 | *
|
---|
106 | * @param in DataOutput to put value into
|
---|
107 | * @param value to be serialized, must be non-negative
|
---|
108 | * @throws IOException
|
---|
109 | */
|
---|
110 |
|
---|
111 | static public void packInt(DataOutput in, int value) throws IOException {
|
---|
112 | if (value < 0) {
|
---|
113 | throw new IllegalArgumentException("negative value: keys=" + value);
|
---|
114 | }
|
---|
115 |
|
---|
116 | while ((value & ~0x7F) != 0) {
|
---|
117 | in.write(((value & 0x7F) | 0x80));
|
---|
118 | value >>>= 7;
|
---|
119 | }
|
---|
120 |
|
---|
121 | in.write((byte) value);
|
---|
122 | }
|
---|
123 |
|
---|
124 | static public int unpackInt(DataInput is) throws IOException {
|
---|
125 | for (int offset = 0, result = 0; offset < 32; offset += 7) {
|
---|
126 | int b = is.readUnsignedByte();
|
---|
127 | result |= (b & 0x7F) << offset;
|
---|
128 | if ((b & 0x80) == 0) {
|
---|
129 | return result;
|
---|
130 | }
|
---|
131 | }
|
---|
132 | throw new Error("Malformed int.");
|
---|
133 | }
|
---|
134 |
|
---|
135 |
|
---|
136 | public static int longHash(final long key) {
|
---|
137 | int h = (int)(key ^ (key >>> 32));
|
---|
138 | h ^= (h >>> 20) ^ (h >>> 12);
|
---|
139 | return h ^ (h >>> 7) ^ (h >>> 4);
|
---|
140 | }
|
---|
141 |
|
---|
142 | /** clone value using serialization */
|
---|
143 | public static <E> E clone(E value, Serializer<E> serializer){
|
---|
144 | try{
|
---|
145 | DataOutput2 out = new DataOutput2();
|
---|
146 | serializer.serialize(out,value);
|
---|
147 | DataInput2 in = new DataInput2(ByteBuffer.wrap(out.copyBytes()), 0);
|
---|
148 |
|
---|
149 | return serializer.deserialize(in,out.pos);
|
---|
150 | }catch(IOException ee){
|
---|
151 | throw new IOError(ee);
|
---|
152 | }
|
---|
153 | }
|
---|
154 |
|
---|
155 | /** expand array size by 1, and put value at given position. No items from original array are lost*/
|
---|
156 | public static Object[] arrayPut(final Object[] array, final int pos, final Object value){
|
---|
157 | final Object[] ret = Arrays.copyOf(array, array.length+1);
|
---|
158 | if(pos<array.length){
|
---|
159 | System.arraycopy(array, pos, ret, pos+1, array.length-pos);
|
---|
160 | }
|
---|
161 | ret[pos] = value;
|
---|
162 | return ret;
|
---|
163 | }
|
---|
164 |
|
---|
165 | public static long[] arrayLongPut(final long[] array, final int pos, final long value) {
|
---|
166 | final long[] ret = Arrays.copyOf(array,array.length+1);
|
---|
167 | if(pos<array.length){
|
---|
168 | System.arraycopy(array,pos,ret,pos+1,array.length-pos);
|
---|
169 | }
|
---|
170 | ret[pos] = value;
|
---|
171 | return ret;
|
---|
172 | }
|
---|
173 |
|
---|
174 |
|
---|
175 | /** Compute nearest bigger power of two*/
|
---|
176 | public static int nextPowTwo(final int value){
|
---|
177 | int ret = 2;
|
---|
178 | while(ret<value)
|
---|
179 | ret = ret<<1;
|
---|
180 | return ret;
|
---|
181 | }
|
---|
182 |
|
---|
183 | /**
|
---|
184 | * Create temporary file in temp folder. All associated db files will be deleted on JVM exit.
|
---|
185 | */
|
---|
186 | public static File tempDbFile() {
|
---|
187 | try{
|
---|
188 | File index = File.createTempFile("mapdb","db");
|
---|
189 | index.deleteOnExit();
|
---|
190 | new File(index.getPath()+StorageDirect.DATA_FILE_EXT).deleteOnExit();
|
---|
191 | new File(index.getPath()+ StorageJournaled.TRANS_LOG_FILE_EXT).deleteOnExit();
|
---|
192 |
|
---|
193 | return index;
|
---|
194 | }catch(IOException e){
|
---|
195 | throw new IOError(e);
|
---|
196 | }
|
---|
197 | }
|
---|
198 |
|
---|
199 | /** check if Operating System is Windows */
|
---|
200 | public static boolean isWindows(){
|
---|
201 | String os = System.getProperty("os.name");
|
---|
202 | return os!=null && (os.toLowerCase().indexOf("win") >= 0);
|
---|
203 |
|
---|
204 | }
|
---|
205 |
|
---|
206 | /** check if Operating System is Android */
|
---|
207 | public static boolean isAndroid(){
|
---|
208 | return "Dalvik".equalsIgnoreCase(System.getProperty("java.vm.name"));
|
---|
209 | }
|
---|
210 |
|
---|
211 |
|
---|
212 | /**
|
---|
213 | * Check if large files can be mapped into memory.
|
---|
214 | * For example 32bit JVM can only address 2GB and large files can not be mapped,
|
---|
215 | * so for 32bit JVM this function returns false.
|
---|
216 | *
|
---|
217 | */
|
---|
218 | public static boolean JVMSupportsLargeMappedFiles() {
|
---|
219 | String prop = System.getProperty("os.arch");
|
---|
220 | if(prop!=null && prop.contains("64")) return true;
|
---|
221 | //TODO better check for 32bit JVM
|
---|
222 | return false;
|
---|
223 | }
|
---|
224 |
|
---|
225 | private static boolean collectionAsMapValueLogged = false;
|
---|
226 |
|
---|
227 | public static void checkMapValueIsNotCollecion(Object value){
|
---|
228 | if(!CC.LOG_HINTS || collectionAsMapValueLogged) return;
|
---|
229 | if(value instanceof Collection || value instanceof Map){
|
---|
230 | collectionAsMapValueLogged = true;
|
---|
231 | LOG.warning("You should not use collections as Map values. MapDB requires key/values to be immutable! Checkout MultiMap example for 1:N mapping.");
|
---|
232 | }
|
---|
233 | }
|
---|
234 |
|
---|
235 | public static void printer(final AtomicLong value){
|
---|
236 | new Thread("printer"){
|
---|
237 | {
|
---|
238 | setDaemon(true);
|
---|
239 | }
|
---|
240 |
|
---|
241 |
|
---|
242 | @Override
|
---|
243 | public void run() {
|
---|
244 | long startValue = value.get();
|
---|
245 | long startTime = System.currentTimeMillis();
|
---|
246 | long old = value.get();
|
---|
247 | while(true){
|
---|
248 |
|
---|
249 | try {
|
---|
250 | Thread.sleep(1000);
|
---|
251 | } catch (InterruptedException e) {
|
---|
252 | return;
|
---|
253 | }
|
---|
254 |
|
---|
255 | long current = value.get();
|
---|
256 | long totalSpeed = 1000*(current-startValue)/(System.currentTimeMillis()-startTime);
|
---|
257 | System.out.print("total: "+current+" - items per last second: "+(current-old)+" - avg items per second: "+totalSpeed+"\r");
|
---|
258 | old = current;
|
---|
259 | }
|
---|
260 |
|
---|
261 | }
|
---|
262 | }.start();
|
---|
263 | }
|
---|
264 |
|
---|
265 | }
|
---|