Skip to content

Commit

Permalink
CLIENT-2764 Support persistent list indexes.
Browse files Browse the repository at this point in the history
  • Loading branch information
BrianNichols committed Jan 26, 2024
1 parent 47873af commit 89ccb2f
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 5 deletions.
62 changes: 58 additions & 4 deletions client/src/com/aerospike/client/cdt/ListOperation.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,49 @@ public class ListOperation {

/**
* Create list create operation.
* Server creates list at given context level. The context is allowed to be beyond list
* boundaries only if pad is set to true. In that case, nil list entries will be inserted to
* satisfy the context position.
* Server creates list at given context level.
*
* @param binName bin name
* @param order list order
* @param pad if true, context is allowed to be beyond list boundaries and insert nil list entries to
* satisfy the ctx position
* @param ctx optional path to nested list. If not defined, the top-level list is used.
*/
public static Operation create(String binName, ListOrder order, boolean pad, CTX... ctx) {
// If context not defined, the set order for top-level bin list.
if (ctx == null || ctx.length == 0) {
return setOrder(binName, order);
}

byte[] bytes = packCreate(order, pad, ctx);
return new Operation(Operation.Type.CDT_MODIFY, binName, Value.get(bytes));
}

/**
* Create list create operation.
* Server creates list at given context level.
*
* @param binName bin name
* @param order list order
* @param pad if true, context is allowed to be beyond list boundaries and insert nil list entries to
* satisfy the ctx position
* @param persistIndex if true, persist list index. A list index improves lookup performance,
* but requires more storage. A list index can be created for a top-level
* ordered list only. Nested and unordered list indexes are not supported.
* @param ctx optional path to nested list. If not defined, the top-level list is used.
*/
public static Operation create(String binName, ListOrder order, boolean pad, boolean persistIndex, CTX... ctx) {
// If context not defined, the set order for top-level bin list.
if (ctx == null || ctx.length == 0) {
return setOrder(binName, order, persistIndex);
}

// Create nested list. persistIndex does not apply here, so ignore it.
byte[] bytes = packCreate(order, pad, ctx);
return new Operation(Operation.Type.CDT_MODIFY, binName, Value.get(bytes));
}

private static byte[] packCreate(ListOrder order, boolean pad, CTX[] ctx) {
Packer packer = new Packer();

// Calculate buffer size.
Expand All @@ -112,7 +145,7 @@ public static Operation create(String binName, ListOrder order, boolean pad, CTX
CDT.init(packer, ctx, SET_TYPE, 1, order.getFlag(pad));
packer.packInt(order.attributes);

return new Operation(Operation.Type.CDT_MODIFY, binName, Value.get(packer.getBuffer()));
return packer.getBuffer();
}

/**
Expand All @@ -124,6 +157,27 @@ public static Operation setOrder(String binName, ListOrder order, CTX... ctx) {
return new Operation(Operation.Type.CDT_MODIFY, binName, Value.get(bytes));
}

/**
* Create set list order operation.
* Server sets list order. Server returns null.
*
* @param binName bin name
* @param order list order
* @param persistIndex if true, persist list index. A list index improves lookup performance,
* but requires more storage. A list index can be created for a top-level
* ordered list only. Nested and unordered list indexes are not supported.
* @param ctx optional path to nested list. If not defined, the top-level list is used.
*/
public static Operation setOrder(String binName, ListOrder order, boolean persistIndex, CTX... ctx) {
int attr = order.attributes;

if (persistIndex) {
attr |= 0x10;
}
byte[] bytes = Pack.pack(ListOperation.SET_TYPE, attr, ctx);
return new Operation(Operation.Type.CDT_MODIFY, binName, Value.get(bytes));
}

/**
* Create default list append operation.
* Server appends value to end of list bin.
Expand Down
49 changes: 48 additions & 1 deletion test/src/com/aerospike/test/sync/basic/TestOperateList.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2012-2023 Aerospike, Inc.
* Copyright 2012-2024 Aerospike, Inc.
*
* Portions may be licensed to Aerospike, Inc. under one or more contributor
* license agreements WHICH ARE COMPATIBLE WITH THE APACHE LICENSE, VERSION 2.0.
Expand Down Expand Up @@ -1205,4 +1205,51 @@ record = client.operate(null, key,
assertEquals(1, list.size());
assertEquals(2, (long)(Long)list.get(0));
}

@Test
public void operateListCreate() {
Key key = new Key(args.namespace, args.set, "oplkey21");

client.delete(null, key);

List<Value> l1 = new ArrayList<Value>();
l1.add(Value.get(3));
l1.add(Value.get(2));
l1.add(Value.get(1));

WritePolicy wp = new WritePolicy();
wp.respondAllOps = true;

// Create list with persisted index.
Record record = client.operate(wp, key,
ListOperation.create(binName, ListOrder.ORDERED, false, true),
ListOperation.appendItems(ListPolicy.Default, binName, l1),
Operation.get(binName)
);

assertRecordFound(key, record);
//System.out.println("Record: " + record);

List<?> results = record.getList(binName);
assertEquals(3, results.size()); // 3 operations equals 3 results.

int i = 0;
Object obj = results.get(i++);
assertNull(obj);

long val = (Long)results.get(i++);
assertEquals(3, val); // appendItems returns 3 for number of items appended.

List<?> list = (List<?>)results.get(i++);
assertEquals(3, list.size());

val = (Long)list.get(0);
assertEquals(1, val); // List is returned sorted, so 1 will be the first item.

val = (Long)list.get(1);
assertEquals(2, val);

val= (Long)list.get(2);
assertEquals(3, val);
}
}

0 comments on commit 89ccb2f

Please sign in to comment.