Convert Cache to a C++ object with a constructor
am: c4f469ad10

Change-Id: Id5b7ab2243085cde7237f91f9c5606dca0fbb309
diff --git a/res_cache.cpp b/res_cache.cpp
index 6ace389..55d9514 100644
--- a/res_cache.cpp
+++ b/res_cache.cpp
@@ -140,14 +140,7 @@
  * * Upping by another 5x for the centralized nature
  * *****************************************
  */
-#define CONFIG_MAX_ENTRIES (64 * 2 * 5)
-
-/* Defaults used for initializing res_params */
-
-// If successes * 100 / total_samples is less than this value, the server is considered failing
-#define SUCCESS_THRESHOLD 75
-// Sample validity in seconds. Set to -1 to disable skipping failing servers.
-#define NSSAMPLE_VALIDITY 1800
+const int CONFIG_MAX_ENTRIES = 64 * 2 * 5;
 
 static time_t _time_now(void) {
     struct timeval tv;
@@ -870,21 +863,71 @@
 /* Maximum time for a thread to wait for an pending request */
 constexpr int PENDING_REQUEST_TIMEOUT = 20;
 
+// lock protecting everything in the resolve_cache_info structs (next ptr, etc)
+static std::mutex cache_mutex;
+static std::condition_variable cv;
+
+// Note that Cache is not thread-safe per se, access to its members must be protected
+// by an external mutex.
+//
+// TODO: move all cache manipulation code here and make data members private.
 struct Cache {
-    int max_entries;
-    int num_entries;
+    Cache() {
+        entries.resize(CONFIG_MAX_ENTRIES);
+        mru_list.mru_prev = mru_list.mru_next = &mru_list;
+    }
+    ~Cache() { flush(); }
+
+    void flush() {
+        for (int nn = 0; nn < CONFIG_MAX_ENTRIES; nn++) {
+            Entry** pnode = (Entry**)&entries[nn];
+
+            while (*pnode) {
+                Entry* node = *pnode;
+                *pnode = node->hlink;
+                entry_free(node);
+            }
+        }
+
+        flushPendingRequests();
+
+        mru_list.mru_next = mru_list.mru_prev = &mru_list;
+        num_entries = 0;
+        last_id = 0;
+
+        LOG(INFO) << "DNS cache flushed";
+    }
+
+    void flushPendingRequests() {
+        pending_req_info* ri = pending_requests.next;
+        while (ri) {
+            pending_req_info* tmp = ri;
+            ri = ri->next;
+            free(tmp);
+        }
+
+        pending_requests.next = nullptr;
+        cv.notify_all();
+    }
+
+    int num_entries = 0;
+
+    // TODO: convert to std::list
     Entry mru_list;
-    int last_id;
-    Entry* entries;
+    int last_id = 0;
+    std::vector<Entry> entries;
+
+    // TODO: convert to std::vector
     struct pending_req_info {
         unsigned int hash;
         struct pending_req_info* next;
-    } pending_requests;
+    } pending_requests{};
 };
 
+// TODO: allocate with new
 struct resolv_cache_info {
     unsigned netid;
-    Cache* cache;
+    Cache* cache;  // TODO: use unique_ptr or embed
     struct resolv_cache_info* next;
     int nscount;
     std::vector<std::string> nameservers;
@@ -898,29 +941,8 @@
     std::unordered_map<int, uint32_t> dns_event_subsampling_map;
 };
 
-// lock protecting everything in the resolve_cache_info structs (next ptr, etc)
-static std::mutex cache_mutex;
-static std::condition_variable cv;
-
 /* gets cache associated with a network, or NULL if none exists */
 static Cache* find_named_cache_locked(unsigned netid) REQUIRES(cache_mutex);
-static int resolv_create_cache_for_net_locked(unsigned netid) REQUIRES(cache_mutex);
-
-static void cache_flush_pending_requests_locked(struct Cache* cache) {
-    Cache::pending_req_info *ri, *tmp;
-    if (!cache) return;
-
-    ri = cache->pending_requests.next;
-
-    while (ri) {
-        tmp = ri;
-        ri = ri->next;
-        free(tmp);
-    }
-
-    cache->pending_requests.next = NULL;
-    cv.notify_all();
-}
 
 // Return true - if there is a pending request in |cache| matching |key|.
 // Return false - if no pending request is found matching the key. Optionally
@@ -986,45 +1008,6 @@
     }
 }
 
-static void cache_flush_locked(Cache* cache) {
-    int nn;
-
-    for (nn = 0; nn < cache->max_entries; nn++) {
-        Entry** pnode = (Entry**) &cache->entries[nn];
-
-        while (*pnode != NULL) {
-            Entry* node = *pnode;
-            *pnode = node->hlink;
-            entry_free(node);
-        }
-    }
-
-    // flush pending request
-    cache_flush_pending_requests_locked(cache);
-
-    cache->mru_list.mru_next = cache->mru_list.mru_prev = &cache->mru_list;
-    cache->num_entries = 0;
-    cache->last_id = 0;
-
-    LOG(INFO) << __func__ << ": *** DNS CACHE FLUSHED ***";
-}
-
-static Cache* resolv_cache_create() {
-    Cache* cache = (Cache*)calloc(sizeof(*cache), 1);
-    if (cache) {
-        cache->max_entries = CONFIG_MAX_ENTRIES;
-        cache->entries = (Entry*) calloc(sizeof(*cache->entries), cache->max_entries);
-        if (cache->entries) {
-            cache->mru_list.mru_prev = cache->mru_list.mru_next = &cache->mru_list;
-            LOG(INFO) << __func__ << ": cache created";
-        } else {
-            free(cache);
-            cache = NULL;
-        }
-    }
-    return cache;
-}
-
 static void cache_dump_mru_locked(Cache* cache) {
     std::string buf;
 
@@ -1051,7 +1034,7 @@
  * table.
  */
 static Entry** _cache_lookup_p(Cache* cache, Entry* key) {
-    int index = key->hash % cache->max_entries;
+    int index = key->hash % CONFIG_MAX_ENTRIES;
     Entry** pnode = (Entry**) &cache->entries[index];
 
     while (*pnode != NULL) {
@@ -1270,9 +1253,9 @@
         return -EEXIST;
     }
 
-    if (cache->num_entries >= cache->max_entries) {
+    if (cache->num_entries >= CONFIG_MAX_ENTRIES) {
         _cache_remove_expired(cache);
-        if (cache->num_entries >= cache->max_entries) {
+        if (cache->num_entries >= CONFIG_MAX_ENTRIES) {
             _cache_remove_oldest(cache);
         }
         // TODO: It looks useless, remove below code after having test to prove it.
@@ -1365,7 +1348,8 @@
 
 }  // namespace
 
-static int resolv_create_cache_for_net_locked(unsigned netid) {
+int resolv_create_cache_for_net(unsigned netid) {
+    std::lock_guard guard(cache_mutex);
     Cache* cache = find_named_cache_locked(netid);
     // Should not happen
     if (cache) {
@@ -1375,24 +1359,14 @@
 
     resolv_cache_info* cache_info = create_cache_info();
     if (!cache_info) return -ENOMEM;
-    cache = resolv_cache_create();
-    if (!cache) {
-        free(cache_info);
-        return -ENOMEM;
-    }
-    cache_info->cache = cache;
     cache_info->netid = netid;
+    cache_info->cache = new Cache;
     cache_info->dns_event_subsampling_map = resolv_get_dns_event_subsampling_map();
     insert_cache_info_locked(cache_info);
 
     return 0;
 }
 
-int resolv_create_cache_for_net(unsigned netid) {
-    std::lock_guard guard(cache_mutex);
-    return resolv_create_cache_for_net_locked(netid);
-}
-
 void resolv_delete_cache_for_net(unsigned netid) {
     std::lock_guard guard(cache_mutex);
 
@@ -1403,9 +1377,7 @@
 
         if (cache_info->netid == netid) {
             prev_cache_info->next = cache_info->next;
-            cache_flush_locked(cache_info->cache);
-            free(cache_info->cache->entries);
-            free(cache_info->cache);
+            delete cache_info->cache;
             free_nameservers_locked(cache_info);
             free(cache_info);
             break;