Merge "implement insertOrReplace()" am: 47851fc01b am: 40899ff9e8
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1662788 Change-Id: Ia4fe20d67bacf5e3e0fa424aeacf1d113db02fdc
This commit is contained in:
committed by
Automerger Merge Worker
commit
cb2064eeff
@@ -98,6 +98,7 @@ public class BpfMap<K extends Struct, V extends Struct> implements AutoCloseable
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Update an existing or create a new key -> value entry in an eBbpf map.
|
* Update an existing or create a new key -> value entry in an eBbpf map.
|
||||||
|
* (use insertOrReplaceEntry() if you need to know whether insert or replace happened)
|
||||||
*/
|
*/
|
||||||
public void updateEntry(K key, V value) throws ErrnoException {
|
public void updateEntry(K key, V value) throws ErrnoException {
|
||||||
writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY);
|
writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_ANY);
|
||||||
@@ -133,6 +134,35 @@ public class BpfMap<K extends Struct, V extends Struct> implements AutoCloseable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update an existing or create a new key -> value entry in an eBbpf map.
|
||||||
|
* Returns true if inserted, false if replaced.
|
||||||
|
* (use updateEntry() if you don't care whether insert or replace happened)
|
||||||
|
* Note: see inline comment below if running concurrently with delete operations.
|
||||||
|
*/
|
||||||
|
public boolean insertOrReplaceEntry(K key, V value)
|
||||||
|
throws ErrnoException {
|
||||||
|
try {
|
||||||
|
writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_NOEXIST);
|
||||||
|
return true; /* insert succeeded */
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
if (e.errno != EEXIST) throw e;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
writeToMapEntry(mMapFd, key.writeToBytes(), value.writeToBytes(), BPF_EXIST);
|
||||||
|
return false; /* replace succeeded */
|
||||||
|
} catch (ErrnoException e) {
|
||||||
|
if (e.errno != ENOENT) throw e;
|
||||||
|
}
|
||||||
|
/* If we reach here somebody deleted after our insert attempt and before our replace:
|
||||||
|
* this implies a race happened. The kernel bpf delete interface only takes a key,
|
||||||
|
* and not the value, so we can safely pretend the replace actually succeeded and
|
||||||
|
* was immediately followed by the other thread's delete, since the delete cannot
|
||||||
|
* observe the potential change to the value.
|
||||||
|
*/
|
||||||
|
return false; /* pretend replace succeeded */
|
||||||
|
}
|
||||||
|
|
||||||
/** Remove existing key from eBpf map. Return false if map was not modified. */
|
/** Remove existing key from eBpf map. Return false if map was not modified. */
|
||||||
public boolean deleteEntry(K key) throws ErrnoException {
|
public boolean deleteEntry(K key) throws ErrnoException {
|
||||||
return deleteMapEntry(mMapFd, key.writeToBytes());
|
return deleteMapEntry(mMapFd, key.writeToBytes());
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ public final class BpfMapTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateBpfMap() throws Exception {
|
public void testUpdateEntry() throws Exception {
|
||||||
final TetherDownstream6Key key = mTestData.keyAt(0);
|
final TetherDownstream6Key key = mTestData.keyAt(0);
|
||||||
final Tether6Value value = mTestData.valueAt(0);
|
final Tether6Value value = mTestData.valueAt(0);
|
||||||
final Tether6Value value2 = mTestData.valueAt(1);
|
final Tether6Value value2 = mTestData.valueAt(1);
|
||||||
@@ -231,6 +231,29 @@ public final class BpfMapTest {
|
|||||||
assertFalse(mTestMap.containsKey(key));
|
assertFalse(mTestMap.containsKey(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInsertOrReplaceEntry() throws Exception {
|
||||||
|
final TetherDownstream6Key key = mTestData.keyAt(0);
|
||||||
|
final Tether6Value value = mTestData.valueAt(0);
|
||||||
|
final Tether6Value value2 = mTestData.valueAt(1);
|
||||||
|
assertFalse(mTestMap.deleteEntry(key));
|
||||||
|
|
||||||
|
// insertOrReplaceEntry will create an entry if it does not exist already.
|
||||||
|
assertTrue(mTestMap.insertOrReplaceEntry(key, value));
|
||||||
|
assertTrue(mTestMap.containsKey(key));
|
||||||
|
final Tether6Value result = mTestMap.getValue(key);
|
||||||
|
assertEquals(value, result);
|
||||||
|
|
||||||
|
// updateEntry will update an entry that already exists.
|
||||||
|
assertFalse(mTestMap.insertOrReplaceEntry(key, value2));
|
||||||
|
assertTrue(mTestMap.containsKey(key));
|
||||||
|
final Tether6Value result2 = mTestMap.getValue(key);
|
||||||
|
assertEquals(value2, result2);
|
||||||
|
|
||||||
|
assertTrue(mTestMap.deleteEntry(key));
|
||||||
|
assertFalse(mTestMap.containsKey(key));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInsertReplaceEntry() throws Exception {
|
public void testInsertReplaceEntry() throws Exception {
|
||||||
final TetherDownstream6Key key = mTestData.keyAt(0);
|
final TetherDownstream6Key key = mTestData.keyAt(0);
|
||||||
|
|||||||
Reference in New Issue
Block a user