Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 45e5a867 authored by Ken Chen's avatar Ken Chen Committed by Gerrit Code Review
Browse files

Merge "Add experiment flag 'max_cache_entries'"

parents 504968e2 1414beed
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ class Experiments {
            "dot_validation_latency_offset_ms",
            "dot_xport_unusable_threshold",
            "keep_listening_udp",
            "max_cache_entries",
            "max_queries_global",
            "mdns_resolution",
            "parallel_lookup_release",
+35 −7
Original line number Diff line number Diff line
@@ -153,7 +153,8 @@ using std::span;
 * * Upping by another 5x for the centralized nature
 * *****************************************
 */
const int CONFIG_MAX_ENTRIES = 64 * 2 * 5;
const int MAX_ENTRIES_DEFAULT = 64 * 2 * 5;
const int MAX_ENTRIES_UPPER_BOUND = 100 * 1000;
constexpr int DNSEVENT_SUBSAMPLING_MAP_DEFAULT_KEY = -1;

static time_t _time_now(void) {
@@ -947,14 +948,14 @@ std::unordered_map<int, uint32_t> resolv_get_dns_event_subsampling_map(bool isMd
//
// TODO: move all cache manipulation code here and make data members private.
struct Cache {
    Cache() {
        entries.resize(CONFIG_MAX_ENTRIES);
    Cache() : max_cache_entries(get_max_cache_entries_from_flag()) {
        entries.resize(max_cache_entries);
        mru_list.mru_prev = mru_list.mru_next = &mru_list;
    }
    ~Cache() { flush(); }

    void flush() {
        for (int nn = 0; nn < CONFIG_MAX_ENTRIES; nn++) {
        for (int nn = 0; nn < max_cache_entries; nn++) {
            Entry** pnode = (Entry**)&entries[nn];

            while (*pnode) {
@@ -985,6 +986,8 @@ struct Cache {
        cv.notify_all();
    }

    int get_max_cache_entries() { return max_cache_entries; }

    int num_entries = 0;

    // TODO: convert to std::list
@@ -997,6 +1000,21 @@ struct Cache {
        unsigned int hash;
        struct pending_req_info* next;
    } pending_requests{};

  private:
    int get_max_cache_entries_from_flag() {
        int entries = android::net::Experiments::getInstance()->getFlag("max_cache_entries",
                                                                        MAX_ENTRIES_DEFAULT);
        // Check both lower and upper bounds to prevent irrational values mistakenly pushed by
        // server.
        if (entries < MAX_ENTRIES_DEFAULT || entries > MAX_ENTRIES_UPPER_BOUND) {
            LOG(ERROR) << "Misconfiguration on max_cache_entries " << entries;
            entries = MAX_ENTRIES_DEFAULT;
        }
        return entries;
    }

    const int max_cache_entries;
};

struct NetConfig {
@@ -1139,7 +1157,7 @@ static void cache_dump_mru_locked(Cache* cache) {
 * table.
 */
static Entry** _cache_lookup_p(Cache* cache, Entry* key) {
    int index = key->hash % CONFIG_MAX_ENTRIES;
    int index = key->hash % cache->get_max_cache_entries();
    Entry** pnode = (Entry**) &cache->entries[index];

    while (*pnode != NULL) {
@@ -1355,9 +1373,9 @@ int resolv_cache_add(unsigned netid, span<const uint8_t> query, span<const uint8
        return -EEXIST;
    }

    if (cache->num_entries >= CONFIG_MAX_ENTRIES) {
    if (cache->num_entries >= cache->get_max_cache_entries()) {
        _cache_remove_expired(cache);
        if (cache->num_entries >= CONFIG_MAX_ENTRIES) {
        if (cache->num_entries >= cache->get_max_cache_entries()) {
            _cache_remove_oldest(cache);
        }
        // TODO: It looks useless, remove below code after having test to prove it.
@@ -2074,3 +2092,13 @@ void resolv_netconfig_dump(DumpWriter& dw, unsigned netid) {
        dw.println("TransportType: %s", transport_type_to_str(info->transportTypes));
    }
}

int resolv_get_max_cache_entries(unsigned netid) {
    std::lock_guard guard(cache_mutex);
    NetConfig* info = find_netconfig_locked(netid);
    if (!info) {
        LOG(WARNING) << __func__ << ": NetConfig for netid " << netid << " not found";
        return -1;
    }
    return info->cache->get_max_cache_entries();
}
 No newline at end of file
+4 −0
Original line number Diff line number Diff line
@@ -139,3 +139,7 @@ android::net::NetworkType convert_network_type(const std::vector<int32_t>& trans

// Dump net configuration log for a given network.
void resolv_netconfig_dump(android::netdutils::DumpWriter& dw, unsigned netid);

// Get the maximum cache size of a network.
// Return positive value on success, -1 on failure.
int resolv_get_max_cache_entries(unsigned netid);
+34 −11
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@
#include <gtest/gtest.h>
#include <netdutils/NetNativeTestBase.h>

#include "Experiments.h"
#include "resolv_cache.h"
#include "resolv_private.h"
#include "stats.h"
@@ -41,12 +42,15 @@ using namespace std::chrono_literals;

using android::netdutils::IPSockAddr;

const std::string kMaxCacheEntriesFlag("persist.device_config.netd_native.max_cache_entries");

constexpr int TEST_NETID_2 = 31;
constexpr int DNS_PORT = 53;

// Constant values sync'd from res_cache.cpp
constexpr int DNS_HEADER_SIZE = 12;
constexpr int MAX_ENTRIES = 64 * 2 * 5;
constexpr int MAX_ENTRIES_DEFAULT = 64 * 2 * 5;
constexpr int MAX_ENTRIES_UPPER_BOUND = 100 * 1000;

namespace {

@@ -558,9 +562,10 @@ TEST_F(ResolvCacheTest, PendingRequest_CacheDestroyed) {
TEST_F(ResolvCacheTest, MaxEntries) {
    EXPECT_EQ(0, cacheCreate(TEST_NETID));
    std::vector<CacheEntry> ces;
    const int max_cache_entries = resolv_get_max_cache_entries(TEST_NETID);

    for (int i = 0; i < 2 * MAX_ENTRIES; i++) {
        std::string qname = fmt::format("cache.{:04d}", i);
    for (int i = 0; i < 2 * max_cache_entries; i++) {
        std::string qname = fmt::format("cache.{:06d}", i);
        SCOPED_TRACE(qname);
        CacheEntry ce = makeCacheEntry(QUERY, qname.data(), ns_c_in, ns_t_a, "1.2.3.4");
        EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
@@ -568,12 +573,12 @@ TEST_F(ResolvCacheTest, MaxEntries) {
        ces.emplace_back(ce);
    }

    for (int i = 0; i < 2 * MAX_ENTRIES; i++) {
        std::string qname = fmt::format("cache.{:04d}", i);
    for (int i = 0; i < 2 * max_cache_entries; i++) {
        std::string qname = fmt::format("cache.{:06d}", i);
        SCOPED_TRACE(qname);
        if (i < MAX_ENTRIES) {
        if (i < max_cache_entries) {
            // Because the cache is LRU, the oldest queries should have been purged,
            // and the most recent MAX_ENTRIES ones should still be present.
            // and the most recent max_cache_entries ones should still be present.
            EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ces[i]));
        } else {
            EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ces[i]));
@@ -584,17 +589,18 @@ TEST_F(ResolvCacheTest, MaxEntries) {
TEST_F(ResolvCacheTest, CacheFull) {
    EXPECT_EQ(0, cacheCreate(TEST_NETID));

    CacheEntry ce1 = makeCacheEntry(QUERY, "cache.0000", ns_c_in, ns_t_a, "1.2.3.4", 100s);
    CacheEntry ce1 = makeCacheEntry(QUERY, "cache.000000", ns_c_in, ns_t_a, "1.2.3.4", 100s);
    EXPECT_EQ(0, cacheAdd(TEST_NETID, ce1));
    EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce1));

    CacheEntry ce2 = makeCacheEntry(QUERY, "cache.0001", ns_c_in, ns_t_a, "1.2.3.4", 1s);
    CacheEntry ce2 = makeCacheEntry(QUERY, "cache.000001", ns_c_in, ns_t_a, "1.2.3.4", 1s);
    EXPECT_EQ(0, cacheAdd(TEST_NETID, ce2));
    EXPECT_TRUE(cacheLookup(RESOLV_CACHE_FOUND, TEST_NETID, ce2));

    // Stuff the resolver cache.
    for (int i = 2; i < MAX_ENTRIES; i++) {
        std::string qname = fmt::format("cache.{:04d}", i);
    const int max_cache_entries = resolv_get_max_cache_entries(TEST_NETID);
    for (int i = 2; i < max_cache_entries; i++) {
        std::string qname = fmt::format("cache.{:06d}", i);
        SCOPED_TRACE(qname);
        CacheEntry ce = makeCacheEntry(QUERY, qname.data(), ns_c_in, ns_t_a, "1.2.3.4", 50s);
        EXPECT_EQ(0, cacheAdd(TEST_NETID, ce));
@@ -617,6 +623,23 @@ TEST_F(ResolvCacheTest, CacheFull) {
    EXPECT_TRUE(cacheLookup(RESOLV_CACHE_NOTFOUND, TEST_NETID, ce1));
}

class ResolvCacheParameterizedTest : public ResolvCacheTest,
                                     public testing::WithParamInterface<int> {};

INSTANTIATE_TEST_SUITE_P(MaxCacheEntries, ResolvCacheParameterizedTest,
                         testing::Values(0, MAX_ENTRIES_UPPER_BOUND + 1),
                         [](const testing::TestParamInfo<int>& info) {
                             return std::to_string(info.param);
                         });

TEST_P(ResolvCacheParameterizedTest, IrrationalCacheSize) {
    // Assign an out-of-bounds value.
    ScopedSystemProperties sp1(kMaxCacheEntriesFlag, std::to_string(GetParam()));
    android::net::Experiments::getInstance()->update();
    EXPECT_EQ(0, cacheCreate(TEST_NETID));
    EXPECT_EQ(MAX_ENTRIES_DEFAULT, resolv_get_max_cache_entries(TEST_NETID));
}

TEST_F(ResolvCacheTest, ResolverSetup) {
    const SetupParams setup = {
            .servers = {"127.0.0.1", "::127.0.0.2", "fe80::3"},