BUG/MINOR: cache: alloc shctx after check config

When running haproxy -c, the cache parser is trying to allocate the size
of the cache. This can be a problem in an environment where the RAM is
limited.

This patch moves the cache allocation in the post_check callback which
is not executed during a -c.

This patch may be backported at least to 2.0 and 1.9. In 1.9, the callbacks
registration mechanism is not the same. So the patch will have to be adapted. No
need to backport it to 1.8, the code is probably too different.
diff --git a/src/cache.c b/src/cache.c
index 1fd8dc6..2ca745a 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -85,6 +85,7 @@
 #define CACHE_ENTRY_MAX_AGE 2147483648U
 
 static struct list caches = LIST_HEAD_INIT(caches);
+static struct list caches_config = LIST_HEAD_INIT(caches_config); /* cache config to init */
 static struct cache *tmp_cache_config = NULL;
 
 DECLARE_STATIC_POOL(pool_head_cache_st, "cache_st", sizeof(struct cache_st));
@@ -149,13 +150,14 @@
 	struct cache *cache;
 	int comp = 0;
 
-	/* resolve the cache name to a ptr in the filter config */
-	list_for_each_entry(cache, &caches, list) {
-		if (!strcmp(cache->id, cconf->c.name)) {
-			free(cconf->c.name);
-			cconf->c.cache = cache;
+	/* Find the cache corresponding to the name in the filter config.  The
+	*  cache will not be referenced now in the filter config because it is
+	*  not fully allocated. This step will be performed during the cache
+	*  post_check.
+	*/
+	list_for_each_entry(cache, &caches_config, list) {
+		if (!strcmp(cache->id, cconf->c.name))
 			goto found;
-		}
 	}
 
 	ha_alert("config: %s '%s': unable to find the cache '%s' referenced by the filter 'cache'.\n",
@@ -1299,12 +1301,9 @@
 
 int cfg_post_parse_section_cache()
 {
-	struct shared_context *shctx;
 	int err_code = 0;
-	int ret_shctx;
 
 	if (tmp_cache_config) {
-		struct cache *cache;
 
 		if (tmp_cache_config->maxblocks <= 0) {
 			ha_alert("Size not specified for cache '%s'\n", tmp_cache_config->id);
@@ -1323,8 +1322,32 @@
 			goto out;
 		}
 
-		ret_shctx = shctx_init(&shctx, tmp_cache_config->maxblocks, CACHE_BLOCKSIZE,
-		                       tmp_cache_config->maxobjsz, sizeof(struct cache), 1);
+		/* add to the list of cache to init and reinit tmp_cache_config
+		 * for next cache section, if any.
+		 */
+		LIST_ADDQ(&caches_config, &tmp_cache_config->list);
+		tmp_cache_config = NULL;
+		return err_code;
+	}
+out:
+	free(tmp_cache_config);
+	tmp_cache_config = NULL;
+	return err_code;
+
+}
+
+int post_check_cache()
+{
+	struct proxy *px;
+	struct cache *back, *cache_config, *cache;
+	struct shared_context *shctx;
+	int ret_shctx;
+	int err_code = 0;
+
+	list_for_each_entry_safe(cache_config, back, &caches_config, list) {
+
+		ret_shctx = shctx_init(&shctx, cache_config->maxblocks, CACHE_BLOCKSIZE,
+		                       cache_config->maxobjsz, sizeof(struct cache), 1);
 
 		if (ret_shctx <= 0) {
 			if (ret_shctx == SHCTX_E_INIT_LOCK)
@@ -1336,14 +1359,38 @@
 			goto out;
 		}
 		shctx->free_block = cache_free_blocks;
-		memcpy(shctx->data, tmp_cache_config, sizeof(struct cache));
+		/* the cache structure is stored in the shctx and added to the
+		 * caches list, we can remove the entry from the caches_config
+		 * list */
+		memcpy(shctx->data, cache_config, sizeof(struct cache));
 		cache = (struct cache *)shctx->data;
 		cache->entries = EB_ROOT_UNIQUE;
 		LIST_ADDQ(&caches, &cache->list);
+		LIST_DEL(&cache_config->list);
+		free(cache_config);
+
+		/* Find all references for this cache in the existing filters
+		 * (over all proxies) and reference it in matching filters.
+		 */
+		for (px = proxies_list; px; px = px->next) {
+			struct flt_conf *fconf;
+			struct cache_flt_conf *cconf;
+
+			list_for_each_entry(fconf, &px->filter_configs, list) {
+				if (fconf->id != cache_store_flt_id)
+					continue;
+
+				cconf = fconf->conf;
+				if (!strcmp(cache->id, cconf->c.name)) {
+					free(cconf->c.name);
+					cconf->c.cache = cache;
+					break;
+				}
+			}
+		}
 	}
+
 out:
-	free(tmp_cache_config);
-	tmp_cache_config = NULL;
 	return err_code;
 
 }
@@ -1545,3 +1592,4 @@
 
 /* config parsers for this section */
 REGISTER_CONFIG_SECTION("cache", cfg_parse_cache, cfg_post_parse_section_cache);
+REGISTER_POST_CHECK(post_check_cache);