10
10
11
11
import org .opensearch .common .collect .Tuple ;
12
12
13
+ import java .math .BigInteger ;
13
14
import java .nio .ByteBuffer ;
14
15
import java .util .Arrays ;
15
16
import java .util .Base64 ;
17
+ import java .util .Collections ;
16
18
import java .util .HashMap ;
17
19
import java .util .List ;
20
+ import java .util .Locale ;
18
21
import java .util .Map ;
19
22
import java .util .function .Function ;
20
23
26
29
public class RemoteStoreUtils {
27
30
public static final int LONG_MAX_LENGTH = String .valueOf (Long .MAX_VALUE ).length ();
28
31
32
+ /**
33
+ * URL safe base 64 character set. This must not be changed as this is used in deriving the base64 equivalent of binary.
34
+ */
35
+ private static final char [] URL_BASE64_CHARSET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_" .toCharArray ();
36
+
37
+ private static Map <Character , Integer > BASE64_CHARSET_IDX_MAP ;
38
+
39
+ static {
40
+ Map <Character , Integer > charToIndexMap = new HashMap <>();
41
+ for (int i = 0 ; i < URL_BASE64_CHARSET .length ; i ++) {
42
+ charToIndexMap .put (URL_BASE64_CHARSET [i ], i );
43
+ }
44
+ BASE64_CHARSET_IDX_MAP = Collections .unmodifiableMap (charToIndexMap );
45
+ }
46
+
29
47
/**
30
48
* This method subtracts given numbers from Long.MAX_VALUE and returns a string representation of the result.
31
49
* The resultant string is guaranteed to be of the same length that of Long.MAX_VALUE. If shorter, we add left padding
32
50
* of 0s to the string.
51
+ *
33
52
* @param num number to get the inverted long string for
34
53
* @return String value of Long.MAX_VALUE - num
35
54
*/
@@ -46,6 +65,7 @@ public static String invertLong(long num) {
46
65
47
66
/**
48
67
* This method converts the given string into long and subtracts it from Long.MAX_VALUE
68
+ *
49
69
* @param str long in string format to be inverted
50
70
* @return long value of the invert result
51
71
*/
@@ -59,6 +79,7 @@ public static long invertLong(String str) {
59
79
60
80
/**
61
81
* Extracts the segment name from the provided segment file name
82
+ *
62
83
* @param filename Segment file name to parse
63
84
* @return Name of the segment that the segment file belongs to
64
85
*/
@@ -79,10 +100,9 @@ public static String getSegmentName(String filename) {
79
100
}
80
101
81
102
/**
82
- *
83
103
* @param mdFiles List of segment/translog metadata files
84
- * @param fn Function to extract PrimaryTerm_Generation and Node Id from metadata file name .
85
- * fn returns null if node id is not part of the file name
104
+ * @param fn Function to extract PrimaryTerm_Generation and Node Id from metadata file name .
105
+ * fn returns null if node id is not part of the file name
86
106
*/
87
107
public static void verifyNoMultipleWriters (List <String > mdFiles , Function <String , Tuple <String , String >> fn ) {
88
108
Map <String , String > nodesByPrimaryTermAndGen = new HashMap <>();
@@ -116,4 +136,43 @@ static String longToUrlBase64(long value) {
116
136
String base64Str = Base64 .getUrlEncoder ().encodeToString (hashBytes );
117
137
return base64Str .substring (0 , base64Str .length () - 1 );
118
138
}
139
+
140
+ static long urlBase64ToLong (String base64Str ) {
141
+ byte [] hashBytes = Base64 .getUrlDecoder ().decode (base64Str );
142
+ return ByteBuffer .wrap (hashBytes ).getLong ();
143
+ }
144
+
145
+ /**
146
+ * Converts an input hash which occupies 64 bits of memory into a composite encoded string. The string will have 2 parts -
147
+ * 1. Base 64 string and 2. Binary String. We will use the first 6 bits for creating the base 64 string.
148
+ * For the second part, we will use the next 14 bits. For eg - A010001010100010.
149
+ */
150
+ static String longToCompositeUrlBase64AndBinaryEncodingUsing20Bits (long value ) {
151
+ return longToCompositeBase64AndBinaryEncoding (value , 20 );
152
+ }
153
+
154
+ /**
155
+ * Converts an input hash which occupies 64 bits of memory into a composite encoded string. The string will have 2 parts -
156
+ * 1. Base 64 string and 2. Binary String. We will use the first 6 bits for creating the base 64 string.
157
+ * For the second part, the rest of the bits will be used as is in string form.
158
+ */
159
+ static String longToCompositeBase64AndBinaryEncoding (long value , int len ) {
160
+ if (len < 7 || len > 64 ) {
161
+ throw new IllegalArgumentException ("In longToCompositeBase64AndBinaryEncoding, len must be between 7 and 64 (both inclusive)" );
162
+ }
163
+ String binaryEncoding = String .format (Locale .ROOT , "%64s" , Long .toBinaryString (value )).replace (' ' , '0' );
164
+ String base64Part = binaryEncoding .substring (0 , 6 );
165
+ String binaryPart = binaryEncoding .substring (6 , len );
166
+ int base64DecimalValue = Integer .valueOf (base64Part , 2 );
167
+ assert base64DecimalValue >= 0 && base64DecimalValue < 64 ;
168
+ return URL_BASE64_CHARSET [base64DecimalValue ] + binaryPart ;
169
+ }
170
+
171
+ static long compositeUrlBase64BinaryEncodingToLong (String encodedValue ) {
172
+ char ch = encodedValue .charAt (0 );
173
+ int base64BitsIntValue = BASE64_CHARSET_IDX_MAP .get (ch );
174
+ String base64PartBinary = Integer .toBinaryString (base64BitsIntValue );
175
+ String binaryString = base64PartBinary + encodedValue .substring (1 );
176
+ return new BigInteger (binaryString , 2 ).longValue ();
177
+ }
119
178
}
0 commit comments