1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements.  See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership.  The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License.  You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 package org.apache.hadoop.yarn.server.timeline.util;
20 
21 
22 import org.apache.hadoop.io.WritableComparator;
23 
24 import java.io.ByteArrayOutputStream;
25 import java.io.IOException;
26 import java.nio.charset.Charset;
27 
28 import static org.apache.hadoop.yarn.server.timeline.GenericObjectMapper.readReverseOrderedLong;
29 
30 public class LeveldbUtils {
31 
32   public static class KeyBuilder {
33     private static final int MAX_NUMBER_OF_KEY_ELEMENTS = 10;
34     private byte[][] b;
35     private boolean[] useSeparator;
36     private int index;
37     private int length;
38 
KeyBuilder(int size)39     public KeyBuilder(int size) {
40       b = new byte[size][];
41       useSeparator = new boolean[size];
42       index = 0;
43       length = 0;
44     }
45 
newInstance()46     public static KeyBuilder newInstance() {
47       return new KeyBuilder(MAX_NUMBER_OF_KEY_ELEMENTS);
48     }
49 
add(String s)50     public KeyBuilder add(String s) {
51       return add(s.getBytes(Charset.forName("UTF-8")), true);
52     }
53 
add(byte[] t)54     public KeyBuilder add(byte[] t) {
55       return add(t, false);
56     }
57 
add(byte[] t, boolean sep)58     public KeyBuilder add(byte[] t, boolean sep) {
59       b[index] = t;
60       useSeparator[index] = sep;
61       length += t.length;
62       if (sep) {
63         length++;
64       }
65       index++;
66       return this;
67     }
68 
getBytes()69     public byte[] getBytes() throws IOException {
70       ByteArrayOutputStream baos = new ByteArrayOutputStream(length);
71       for (int i = 0; i < index; i++) {
72         baos.write(b[i]);
73         if (i < index - 1 && useSeparator[i]) {
74           baos.write(0x0);
75         }
76       }
77       return baos.toByteArray();
78     }
79 
getBytesForLookup()80     public byte[] getBytesForLookup() throws IOException {
81       ByteArrayOutputStream baos = new ByteArrayOutputStream(length);
82       for (int i = 0; i < index; i++) {
83         baos.write(b[i]);
84         if (useSeparator[i]) {
85           baos.write(0x0);
86         }
87       }
88       return baos.toByteArray();
89     }
90   }
91 
92   public static class KeyParser {
93     private final byte[] b;
94     private int offset;
95 
KeyParser(byte[] b, int offset)96     public KeyParser(byte[] b, int offset) {
97       this.b = b;
98       this.offset = offset;
99     }
100 
getNextString()101     public String getNextString() throws IOException {
102       if (offset >= b.length) {
103         throw new IOException(
104             "tried to read nonexistent string from byte array");
105       }
106       int i = 0;
107       while (offset + i < b.length && b[offset + i] != 0x0) {
108         i++;
109       }
110       String s = new String(b, offset, i, Charset.forName("UTF-8"));
111       offset = offset + i + 1;
112       return s;
113     }
114 
getNextLong()115     public long getNextLong() throws IOException {
116       if (offset + 8 >= b.length) {
117         throw new IOException("byte array ran out when trying to read long");
118       }
119       long l = readReverseOrderedLong(b, offset);
120       offset += 8;
121       return l;
122     }
123 
getOffset()124     public int getOffset() {
125       return offset;
126     }
127   }
128 
129   /**
130    * Returns true if the byte array begins with the specified prefix.
131    */
prefixMatches(byte[] prefix, int prefixlen, byte[] b)132   public static boolean prefixMatches(byte[] prefix, int prefixlen,
133       byte[] b) {
134     if (b.length < prefixlen) {
135       return false;
136     }
137     return WritableComparator.compareBytes(prefix, 0, prefixlen, b, 0,
138         prefixlen) == 0;
139   }
140 
141 }
142