3333
3434/**
3535 * {@link IndexWriter} takes care of writing <a href="https://redis.io/topics/indexes">secondary index</a> structures to
36- * Redis. Depending on the type of {@link IndexedData} it uses eg. Sets with specific names to add actually referenced
37- * keys to. While doing so {@link IndexWriter} also keeps track of all indexes associated with the root types key, which
36+ * Redis. Depending on the type of {@link IndexedData}, it uses Sets with specific names to add actually referenced keys
37+ * to. While doing so {@link IndexWriter} also keeps track of all indexes associated with the root types key, which
3838 * allows to remove the root key from all indexes in case of deletion.
3939 *
4040 * @author Christoph Strobl
4141 * @author Rob Winch
42+ * @author Mark Paluch
4243 * @since 1.7
4344 */
4445class IndexWriter {
4546
47+ private static final byte [] SEPARATOR = ":" .getBytes ();
48+ private static final byte [] IDX = "idx" .getBytes ();
49+
4650 private final RedisConnection connection ;
4751 private final RedisConverter converter ;
4852
4953 /**
5054 * Creates new {@link IndexWriter}.
5155 *
52- * @param keyspace The key space to write index values to. Must not be {@literal null}.
5356 * @param connection must not be {@literal null}.
5457 * @param converter must not be {@literal null}.
5558 */
@@ -127,7 +130,7 @@ public void removeKeyFromIndexes(String keyspace, Object key) {
127130 Assert .notNull (key , "Key must not be null" );
128131
129132 byte [] binKey = toBytes (key );
130- byte [] indexHelperKey = ByteUtils . concatAll ( toBytes ( keyspace + ":" ) , binKey , toBytes ( ":idx" ) );
133+ byte [] indexHelperKey = createIndexKey ( keyspace , binKey );
131134
132135 for (byte [] indexKey : connection .sMembers (indexHelperKey )) {
133136
@@ -147,10 +150,10 @@ public void removeKeyFromIndexes(String keyspace, Object key) {
147150 */
148151 public void removeAllIndexes (String keyspace ) {
149152
150- Set <byte []> potentialIndex = connection .keys (toBytes (keyspace + ": *" ));
153+ Set <byte []> potentialIndex = connection .keys (createIndexKey (keyspace , " *" ));
151154
152155 if (!potentialIndex .isEmpty ()) {
153- connection .del (potentialIndex .toArray (new byte [potentialIndex . size () ][]));
156+ connection .del (potentialIndex .toArray (new byte [0 ][]));
154157 }
155158 }
156159
@@ -162,7 +165,7 @@ private void removeKeyFromExistingIndexes(byte[] key, Iterable<IndexedData> inde
162165 }
163166
164167 /**
165- * Remove given key from all indexes matching {@link IndexedData#getIndexName()}:
168+ * Remove given key from all indexes matching {@link IndexedData#getIndexName()}.
166169 *
167170 * @param key
168171 * @param indexedData
@@ -171,8 +174,7 @@ protected void removeKeyFromExistingIndexes(byte[] key, IndexedData indexedData)
171174
172175 Assert .notNull (indexedData , "IndexedData must not be null" );
173176
174- Set <byte []> existingKeys = connection
175- .keys (toBytes (indexedData .getKeyspace () + ":" + indexedData .getIndexName () + ":*" ));
177+ Set <byte []> existingKeys = connection .keys (createIndexKey (indexedData .getKeyPrefix (), "*" ));
176178
177179 if (!CollectionUtils .isEmpty (existingKeys )) {
178180 for (byte [] existingKey : existingKeys ) {
@@ -216,30 +218,66 @@ protected void addKeyToIndex(byte[] key, IndexedData indexedData) {
216218 return ;
217219 }
218220
219- byte [] indexKey = toBytes (indexedData .getKeyspace () + ":" + indexedData . getIndexName () + ":" );
221+ byte [] indexKey = toBytes (indexedData .getKeyPrefix (), SEPARATOR );
220222 indexKey = ByteUtils .concat (indexKey , toBytes (value ));
221223 connection .sAdd (indexKey , key );
222224
223225 // keep track of indexes used for the object
224- connection .sAdd (ByteUtils . concatAll ( toBytes ( indexedData .getKeyspace () + ":" ) , key , toBytes ( ":idx" ) ), indexKey );
226+ connection .sAdd (createIndexKey ( indexedData .getKeyspace (), key ), indexKey );
225227 } else if (indexedData instanceof GeoIndexedPropertyValue propertyValue ) {
226228
227229 Object value = propertyValue .getValue ();
228230 if (value == null ) {
229231 return ;
230232 }
231233
232- byte [] indexKey = toBytes (indexedData .getKeyspace () + ":" + indexedData . getIndexName ());
234+ byte [] indexKey = toBytes (indexedData .getKeyPrefix ());
233235 connection .geoAdd (indexKey , propertyValue .getPoint (), key );
234236
235237 // keep track of indexes used for the object
236- connection .sAdd (ByteUtils . concatAll ( toBytes ( indexedData .getKeyspace () + ":" ) , key , toBytes ( ":idx" ) ), indexKey );
238+ connection .sAdd (createIndexKey ( indexedData .getKeyspace (), key ), indexKey );
237239 } else {
238240 throw new IllegalArgumentException (
239241 String .format ("Cannot write index data for unknown index type %s" , indexedData .getClass ()));
240242 }
241243 }
242244
245+ private byte [] createIndexKey (String keyspace , byte [] key ) {
246+ return createIndexKey (keyspace , key , IDX );
247+ }
248+
249+ private byte [] createIndexKey (Object ... items ) {
250+
251+ Object [] elements = new Object [items .length + (items .length - 1 )];
252+
253+ int j = 0 ;
254+ for (int i = 0 ; i < items .length ; i ++) {
255+
256+ elements [j ++] = items [i ];
257+ if (items .length - 1 > i ) {
258+ elements [j ++] = SEPARATOR ;
259+ }
260+ }
261+
262+ return toBytes (elements );
263+ }
264+
265+ private byte [] toBytes (Object ... values ) {
266+
267+ byte [][] arrays = new byte [values .length ][];
268+
269+ for (int i = 0 ; i < values .length ; i ++) {
270+
271+ if (values [i ] instanceof byte [] bb ) {
272+ arrays [i ] = bb ;
273+ } else {
274+ arrays [i ] = toBytes (values [i ]);
275+ }
276+ }
277+
278+ return ByteUtils .concatAll (arrays );
279+ }
280+
243281 private byte [] toBytes (@ Nullable Object source ) {
244282
245283 if (source == null ) {
0 commit comments