Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit da4ab0a

Browse files
authored
Add compression support for PHP Sessions (#2473)
* Add compression support for PHP Sessions Previously, compression was available for standard data but not for session handling. This update enables the compression of PHP sessions, allowing for more efficient Redis memory usage. * Move session compress/uncompress logic to helper functions * Change session_compress_data to always set the out arguments and adjust PS_READ_FUNC
1 parent 5f1eecf commit da4ab0a

4 files changed

Lines changed: 126 additions & 13 deletions

File tree

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ redis.session.lock_wait_time = 50000
118118
redis.session.lock_retries = 2000
119119
~~~
120120

121+
### Session compression
122+
123+
Following INI variables can be used to configure session compression:
124+
~~~
125+
; Should session compression be enabled? Possible values are zstd, lzf, lz4, none. Defaults to: none
126+
redis.session.compression = zstd
127+
; What compression level should be used? Compression level depends on used library. For most deployments range 1-9 should be fine. Defaults to: 3
128+
redis.session.compression_level = 3
129+
~~~
130+
121131
## Running the unit tests
122132

123133
phpredis uses a small custom unit test suite for testing functionality of the various classes. To run tests, simply do the following:

cluster.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,13 @@ To enable, set the following INI variable:
206206
redis.session.early_refresh = 1
207207
```
208208
Note: This is disabled by default since it may significantly reduce the session lifetime for long-running scripts. Redis server version 6.2+ required.
209+
210+
### Session compression
211+
212+
Following INI variables can be used to configure session compression:
213+
~~~
214+
; Should session compression be enabled? Possible values are zstd, lzf, lz4, none. Defaults to: none
215+
redis.session.compression = zstd
216+
; What compression level should be used? Compression level depends on used library. For most deployments range 1-9 should be fine. Defaults to: 3
217+
redis.session.compression_level = 3
218+
~~~

redis.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,8 @@ PHP_INI_BEGIN()
115115
PHP_INI_ENTRY("redis.session.lock_retries", "100", PHP_INI_ALL, NULL)
116116
PHP_INI_ENTRY("redis.session.lock_wait_time", "20000", PHP_INI_ALL, NULL)
117117
PHP_INI_ENTRY("redis.session.early_refresh", "0", PHP_INI_ALL, NULL)
118+
PHP_INI_ENTRY("redis.session.compression", "none", PHP_INI_ALL, NULL)
119+
PHP_INI_ENTRY("redis.session.compression_level", "3", PHP_INI_ALL, NULL)
118120
PHP_INI_END()
119121

120122
static const zend_module_dep redis_deps[] = {

redis_session.c

Lines changed: 104 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,66 @@ static int session_gc_maxlifetime(void) {
140140
return value;
141141
}
142142

143+
/* Retrieve redis.session.compression from php.ini */
144+
static int session_compression_type(void) {
145+
#ifdef HAVE_REDIS_LZF
146+
if(strncasecmp(INI_STR("redis.session.compression"), "lzf", sizeof("lzf") - 1) == 0) {
147+
return REDIS_COMPRESSION_LZF;
148+
}
149+
#endif
150+
#ifdef HAVE_REDIS_ZSTD
151+
if(strncasecmp(INI_STR("redis.session.compression"), "zstd", sizeof("zstd") - 1) == 0) {
152+
return REDIS_COMPRESSION_ZSTD;
153+
}
154+
#endif
155+
#ifdef HAVE_REDIS_LZ4
156+
if(strncasecmp(INI_STR("redis.session.compression"), "lz4", sizeof("lz4") - 1) == 0) {
157+
return REDIS_COMPRESSION_LZ4;
158+
}
159+
#endif
160+
if(strncasecmp(INI_STR("redis.session.compression"), "none", sizeof("none") - 1) == 0) {
161+
return REDIS_COMPRESSION_NONE;
162+
}
163+
164+
// E_NOTICE when outside of valid values
165+
php_error_docref(NULL, E_NOTICE, "redis.session.compression is outside of valid values, disabling");
166+
167+
return REDIS_COMPRESSION_NONE;
168+
}
169+
170+
/* Helper to compress session data */
171+
static int
172+
session_compress_data(RedisSock *redis_sock, char *data, size_t len,
173+
char **compressed_data, size_t *compressed_len)
174+
{
175+
if (redis_sock->compression) {
176+
if(redis_compress(redis_sock, compressed_data, compressed_len, data, len)) {
177+
return 1;
178+
}
179+
}
180+
181+
*compressed_data = data;
182+
*compressed_len = len;
183+
184+
return 0;
185+
}
186+
187+
/* Helper to uncompress session data */
188+
static int
189+
session_uncompress_data(RedisSock *redis_sock, char *data, size_t len,
190+
char **decompressed_data, size_t *decompressed_len) {
191+
if (redis_sock->compression) {
192+
if(redis_uncompress(redis_sock, decompressed_data, decompressed_len, data, len)) {
193+
return 1;
194+
}
195+
}
196+
197+
*decompressed_data = data;
198+
*decompressed_len = len;
199+
200+
return 0;
201+
}
202+
143203
/* Send a command to Redis. Returns byte count written to socket (-1 on failure) */
144204
static int redis_simple_cmd(RedisSock *redis_sock, char *cmd, int cmdlen,
145205
char **reply, int *replylen)
@@ -478,6 +538,9 @@ PS_OPEN_FUNC(redis)
478538
redis_sock->dbNumber = db;
479539
}
480540

541+
redis_sock->compression = session_compression_type();
542+
redis_sock->compression_level = INI_INT("redis.session.compression_level");
543+
481544
if (Z_TYPE(context) == IS_ARRAY) {
482545
redis_sock_set_stream_context(redis_sock, &context);
483546
}
@@ -685,10 +748,10 @@ PS_UPDATE_TIMESTAMP_FUNC(redis)
685748
*/
686749
PS_READ_FUNC(redis)
687750
{
688-
char *resp, *cmd;
689-
int resp_len, cmd_len;
751+
char *resp, *cmd, *compressed_buf;
752+
int resp_len, cmd_len, compressed_free;
690753
const char *skey = ZSTR_VAL(key);
691-
size_t skeylen = ZSTR_LEN(key);
754+
size_t skeylen = ZSTR_LEN(key), compressed_len;
692755

693756
if (!skeylen) return FAILURE;
694757

@@ -737,8 +800,13 @@ PS_READ_FUNC(redis)
737800
if (resp_len < 0) {
738801
*val = ZSTR_EMPTY_ALLOC();
739802
} else {
740-
*val = zend_string_init(resp, resp_len, 0);
803+
compressed_free = session_uncompress_data(redis_sock, resp, resp_len, &compressed_buf, &compressed_len);
804+
*val = zend_string_init(compressed_buf, compressed_len, 0);
805+
if (compressed_free) {
806+
efree(compressed_buf); // Free the buffer allocated by redis_uncompress
807+
}
741808
}
809+
742810
efree(resp);
743811

744812
return SUCCESS;
@@ -749,10 +817,10 @@ PS_READ_FUNC(redis)
749817
*/
750818
PS_WRITE_FUNC(redis)
751819
{
752-
char *cmd, *response;
753-
int cmd_len, response_len;
820+
char *cmd, *response, *compressed_buf = NULL;
821+
int cmd_len, response_len, compressed_free = 0;
754822
const char *skey = ZSTR_VAL(key), *sval = ZSTR_VAL(val);
755-
size_t skeylen = ZSTR_LEN(key), svallen = ZSTR_LEN(val);
823+
size_t skeylen = ZSTR_LEN(key), svallen = ZSTR_LEN(val), compressed_len = 0;
756824

757825
if (!skeylen) return FAILURE;
758826

@@ -767,8 +835,15 @@ PS_WRITE_FUNC(redis)
767835
/* send SET command */
768836
zend_string *session = redis_session_key(redis_sock, skey, skeylen);
769837

838+
compressed_free = session_compress_data(redis_sock, ZSTR_VAL(val), ZSTR_LEN(val), &compressed_buf, &compressed_len);
839+
sval = compressed_buf;
840+
svallen = compressed_len;
841+
770842
cmd_len = REDIS_SPPRINTF(&cmd, "SETEX", "Sds", session, session_gc_maxlifetime(), sval, svallen);
771843
zend_string_release(session);
844+
if (compressed_free) {
845+
efree(compressed_buf);
846+
}
772847

773848
if (!write_allowed(redis_sock, &pool->lock_status)) {
774849
php_error_docref(NULL, E_WARNING, "Unable to write session: session lock not held");
@@ -942,6 +1017,9 @@ PS_OPEN_FUNC(rediscluster) {
9421017
c->flags->prefix = CLUSTER_DEFAULT_PREFIX();
9431018
}
9441019

1020+
c->flags->compression = session_compression_type();
1021+
c->flags->compression_level = INI_INT("redis.session.compression_level");
1022+
9451023
redis_sock_set_auth(c->flags, user, pass);
9461024

9471025
if ((context = REDIS_HASH_STR_FIND_TYPE_STATIC(ht_conf, "stream", IS_ARRAY)) != NULL) {
@@ -1142,8 +1220,9 @@ PS_UPDATE_TIMESTAMP_FUNC(rediscluster) {
11421220
PS_READ_FUNC(rediscluster) {
11431221
redisCluster *c = PS_GET_MOD_DATA();
11441222
clusterReply *reply;
1145-
char *cmd, *skey;
1146-
int cmdlen, skeylen, free_flag;
1223+
char *cmd, *skey, *compressed_buf;
1224+
int cmdlen, skeylen, free_flag, compressed_free;
1225+
size_t compressed_len;
11471226
short slot;
11481227

11491228
/* Set up our command and slot information */
@@ -1181,7 +1260,11 @@ PS_READ_FUNC(rediscluster) {
11811260
if (reply->str == NULL) {
11821261
*val = ZSTR_EMPTY_ALLOC();
11831262
} else {
1184-
*val = zend_string_init(reply->str, reply->len, 0);
1263+
compressed_free = session_uncompress_data(c->flags, reply->str, reply->len, &compressed_buf, &compressed_len);
1264+
*val = zend_string_init(compressed_buf, compressed_len, 0);
1265+
if (compressed_free) {
1266+
efree(compressed_buf); // Free the buffer allocated by redis_uncompress
1267+
}
11851268
}
11861269

11871270
free_flag = 1;
@@ -1198,16 +1281,24 @@ PS_READ_FUNC(rediscluster) {
11981281
PS_WRITE_FUNC(rediscluster) {
11991282
redisCluster *c = PS_GET_MOD_DATA();
12001283
clusterReply *reply;
1201-
char *cmd, *skey;
1202-
int cmdlen, skeylen;
1284+
char *cmd, *skey, *compressed_buf = NULL, *sval = ZSTR_VAL(val);
1285+
int cmdlen, skeylen, compressed_free = 0, svallen = ZSTR_LEN(val);
12031286
short slot;
1287+
size_t compressed_len = 0;
1288+
1289+
compressed_free = session_compress_data(c->flags, sval, svallen, &compressed_buf, &compressed_len);
1290+
sval = compressed_buf;
1291+
svallen = compressed_len;
12041292

12051293
/* Set up command and slot info */
12061294
skey = cluster_session_key(c, ZSTR_VAL(key), ZSTR_LEN(key), &skeylen, &slot);
12071295
cmdlen = redis_spprintf(NULL, NULL, &cmd, "SETEX", "sds", skey,
12081296
skeylen, session_gc_maxlifetime(),
1209-
ZSTR_VAL(val), ZSTR_LEN(val));
1297+
sval, svallen);
12101298
efree(skey);
1299+
if (compressed_free) {
1300+
efree(compressed_buf);
1301+
}
12111302

12121303
/* Attempt to send command */
12131304
c->readonly = 0;

0 commit comments

Comments
 (0)