1 /*
2 ** Zabbix
3 ** Copyright (C) 2001-2021 Zabbix SIA
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation; either version 2 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program; if not, write to the Free Software
17 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18 **/
19 
20 #include "common.h"
21 #include "ipc.h"
22 #include "log.h"
23 
24 #include "zbxalgo.h"
25 #include "memalloc.h"
26 
27 #include "strpool.h"
28 
29 extern char		*CONFIG_FILE;
30 
31 static zbx_strpool_t	strpool;
32 
33 static zbx_hash_t	__strpool_hash_func(const void *data);
34 static int		__strpool_compare_func(const void *d1, const void *d2);
35 
36 ZBX_MEM_FUNC_DECL(__strpool);
37 
38 #define INIT_HASHSET_SIZE	100
39 #define	REFCOUNT_FIELD_SIZE	sizeof(zbx_uint32_t)
40 
41 /* private strpool functions */
42 
__strpool_hash_func(const void * data)43 static zbx_hash_t	__strpool_hash_func(const void *data)
44 {
45 	return ZBX_DEFAULT_STRING_HASH_FUNC((char *)data + REFCOUNT_FIELD_SIZE);
46 }
47 
__strpool_compare_func(const void * d1,const void * d2)48 static int	__strpool_compare_func(const void *d1, const void *d2)
49 {
50 	return strcmp((char *)d1 + REFCOUNT_FIELD_SIZE, (char *)d2 + REFCOUNT_FIELD_SIZE);
51 }
52 
53 ZBX_MEM_FUNC_IMPL(__strpool, strpool.mem_info);
54 
55 /* public strpool interface */
56 
zbx_strpool_create(size_t size)57 void	zbx_strpool_create(size_t size)
58 {
59 	const char	*__function_name = "zbx_strpool_create";
60 
61 	key_t		shm_key;
62 
63 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
64 
65 	if (-1 == (shm_key = zbx_ftok(CONFIG_FILE, ZBX_IPC_STRPOOL_ID)))
66 	{
67 		zabbix_log(LOG_LEVEL_CRIT, "cannot create IPC key for string pool");
68 		exit(EXIT_FAILURE);
69 	}
70 
71 	zbx_mem_create(&strpool.mem_info, shm_key, ZBX_NO_MUTEX, size, "string pool", "CacheSize", 0);
72 
73 	strpool.hashset = __strpool_mem_malloc_func(NULL, sizeof(zbx_hashset_t));
74 	zbx_hashset_create_ext(strpool.hashset, INIT_HASHSET_SIZE,
75 				__strpool_hash_func, __strpool_compare_func, NULL,
76 				__strpool_mem_malloc_func, __strpool_mem_realloc_func, __strpool_mem_free_func);
77 
78 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
79 }
80 
zbx_strpool_destroy()81 void	zbx_strpool_destroy()
82 {
83 	const char	*__function_name = "zbx_strpool_destroy";
84 
85 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
86 
87 	zbx_mem_destroy(strpool.mem_info);
88 
89 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
90 }
91 
zbx_strpool_intern(const char * str)92 const char	*zbx_strpool_intern(const char *str)
93 {
94 	void		*record;
95 	zbx_uint32_t	*refcount;
96 
97 	record = zbx_hashset_search(strpool.hashset, str - REFCOUNT_FIELD_SIZE);
98 
99 	if (NULL == record)
100 	{
101 		record = zbx_hashset_insert_ext(strpool.hashset, str - REFCOUNT_FIELD_SIZE,
102 				REFCOUNT_FIELD_SIZE + strlen(str) + 1, REFCOUNT_FIELD_SIZE);
103 		*(zbx_uint32_t *)record = 0;
104 	}
105 
106 	refcount = (zbx_uint32_t *)record;
107 	(*refcount)++;
108 
109 	return (char *)record + REFCOUNT_FIELD_SIZE;
110 }
111 
zbx_strpool_acquire(const char * str)112 const char	*zbx_strpool_acquire(const char *str)
113 {
114 	zbx_uint32_t	*refcount;
115 
116 	refcount = (zbx_uint32_t *)(str - REFCOUNT_FIELD_SIZE);
117 	(*refcount)++;
118 
119 	return str;
120 }
121 
zbx_strpool_release(const char * str)122 void	zbx_strpool_release(const char *str)
123 {
124 	zbx_uint32_t	*refcount;
125 
126 	refcount = (zbx_uint32_t *)(str - REFCOUNT_FIELD_SIZE);
127 	if (0 == --(*refcount))
128 		zbx_hashset_remove(strpool.hashset, str - REFCOUNT_FIELD_SIZE);
129 }
130 
zbx_strpool_clear()131 void	zbx_strpool_clear()
132 {
133 	const char	*__function_name = "zbx_strpool_clear";
134 
135 	zabbix_log(LOG_LEVEL_DEBUG, "In %s()", __function_name);
136 
137 	zbx_mem_clear(strpool.mem_info);
138 
139 	strpool.hashset = __strpool_mem_malloc_func(NULL, sizeof(zbx_hashset_t));
140 	zbx_hashset_create_ext(strpool.hashset, INIT_HASHSET_SIZE,
141 				__strpool_hash_func, __strpool_compare_func, NULL,
142 				__strpool_mem_malloc_func, __strpool_mem_realloc_func, __strpool_mem_free_func);
143 
144 	zabbix_log(LOG_LEVEL_DEBUG, "End of %s()", __function_name);
145 }
146 
zbx_strpool_info()147 const zbx_strpool_t	*zbx_strpool_info()
148 {
149 	return &strpool;
150 }
151