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:
Maciej Żenczykowski
2021-04-06 09:17:40 +00:00
committed by Automerger Merge Worker
2 changed files with 54 additions and 1 deletions

View File

@@ -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.
* (use insertOrReplaceEntry() if you need to know whether insert or replace happened)
*/
public void updateEntry(K key, V value) throws ErrnoException {
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. */
public boolean deleteEntry(K key) throws ErrnoException {
return deleteMapEntry(mMapFd, key.writeToBytes());

View File

@@ -209,7 +209,7 @@ public final class BpfMapTest {
}
@Test
public void testUpdateBpfMap() throws Exception {
public void testUpdateEntry() throws Exception {
final TetherDownstream6Key key = mTestData.keyAt(0);
final Tether6Value value = mTestData.valueAt(0);
final Tether6Value value2 = mTestData.valueAt(1);
@@ -231,6 +231,29 @@ public final class BpfMapTest {
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
public void testInsertReplaceEntry() throws Exception {
final TetherDownstream6Key key = mTestData.keyAt(0);