diff --git a/src/Makefile b/src/Makefile index cad5de19..3721ab8a 100644 --- a/src/Makefile +++ b/src/Makefile @@ -146,6 +146,9 @@ endif REDIS_SERVER_NAME=redis-server REDIS_SENTINEL_NAME=redis-sentinel REDIS_SERVER_OBJ=adlist.o quicklist.o ae.o anet.o dict.o server.o sds.o zmalloc.o lzf_c.o lzf_d.o pqsort.o zipmap.o sha1.o ziplist.o release.o networking.o util.o object.o db.o replication.o rdb.o t_string.o t_list.o t_set.o t_zset.o t_hash.o config.o aof.o msqueue.o aof_buf_queue.o pubsub.o multi.o debug.o sort.o intset.o syncio.o cluster.o crc16.o endianconv.o slowlog.o scripting.o bio.o rio.o rand.o memtest.o crc64.o bitops.o sentinel.o notify.o setproctitle.o blocked.o hyperloglog.o latency.o sparkline.o redis-check-rdb.o redis-check-aof.o geo.o lazyfree.o module.o evict.o expire.o geohash.o geohash_helper.o childinfo.o defrag.o siphash.o rax.o memcached.o memcached_parser.o redis_oplog.o +ifeq ($(uname_S),Darwin) + REDIS_SERVER_OBJ += pthread_spinlock.o +endif REDIS_CLI_NAME=redis-cli REDIS_CLI_OBJ=anet.o adlist.o redis-cli.o zmalloc.o release.o anet.o ae.o crc64.o REDIS_BENCHMARK_NAME=redis-benchmark diff --git a/src/aof_buf_queue.h b/src/aof_buf_queue.h index eae533c1..aa2ddf3c 100644 --- a/src/aof_buf_queue.h +++ b/src/aof_buf_queue.h @@ -40,6 +40,10 @@ #include "msqueue.h" #include "util.h" +#ifdef __APPLE__ +#define pthread_yield sched_yield +#endif + #define REDIS_AOF_BUF_QUEUE_DEFAULT_LIMIT (1 << 30) #define REDIS_AOF_BUF_QUEUE_MIN_LIMIT (256*1024*1024) #define AOF_BIO_LATENCY_LOG_RATE_US (30*1000*1000) //30 seconds diff --git a/src/debug.c b/src/debug.c index 7d7b9ba8..7f741ac6 100644 --- a/src/debug.c +++ b/src/debug.c @@ -584,7 +584,11 @@ void _serverAssertPrintClientInfo(const client *c) { bugReportStart(); serverLog(LL_WARNING,"=== ASSERTION FAILED CLIENT CONTEXT ==="); + #if defined(__APPLE__) + serverLog(LL_WARNING,"client->flags = %llu", c->flags); + #elif (defined(__linux__) && defined(__GLIBC__)) serverLog(LL_WARNING,"client->flags = %ld", c->flags); + #endif serverLog(LL_WARNING,"client->fd = %d", c->fd); serverLog(LL_WARNING,"client->argc = %d", c->argc); for (j=0; j < c->argc; j++) { diff --git a/src/endianconv.h b/src/endianconv.h index 72b19b75..ab9444c2 100644 --- a/src/endianconv.h +++ b/src/endianconv.h @@ -52,8 +52,10 @@ uint64_t intrev64(uint64_t v); #define intrev16ifbe(v) (v) #define intrev32ifbe(v) (v) #define intrev64ifbe(v) (v) +#ifndef __APPLE__ #define ntohll(v) intrev64(v) #define htonll(v) intrev64(v) +#endif #else #define memrev16ifbe(p) memrev16(p) #define memrev32ifbe(p) memrev32(p) diff --git a/src/memcached_parser.c b/src/memcached_parser.c index aaec23b7..9e2527c1 100644 --- a/src/memcached_parser.c +++ b/src/memcached_parser.c @@ -28,6 +28,21 @@ #include "server.h" #include "endianconv.h" +#ifdef __APPLE__ +void *memrchr(char *s,int c,int n) { + char *end = s + n; + + do { + --end; + if (c == (int)(*end)) { + return end; + } + } while(s != end); + + return NULL; +} +#endif + extern void addCommandStats(client *c); extern void setProtocolError(const char *errstr, client *c, int pos); extern int time_independent_strcmp(char *a, char *b); diff --git a/src/msqueue.h b/src/msqueue.h index c93f0890..1ba27767 100644 --- a/src/msqueue.h +++ b/src/msqueue.h @@ -30,6 +30,9 @@ #ifndef __MSQUEUE_H__ #define __MSQUEUE_H__ #include +#ifdef __APPLE__ + #include "pthread_spinlock.h" +#endif typedef struct queueNode { struct queueNode *next; diff --git a/src/pthread_spinlock.c b/src/pthread_spinlock.c new file mode 100644 index 00000000..57a6b50c --- /dev/null +++ b/src/pthread_spinlock.c @@ -0,0 +1,72 @@ +/* pthread spinklock macos implementation + * + * Copyright (c) 2019-2021, wei.kukey + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "pthread_spinlock.h" +#include +#include + +#define UNUSED(V) ((void) V) + +int pthread_spin_init(pthread_spinlock_t *lock, int pshared) { + __asm__ __volatile__ ("" ::: "memory"); + UNUSED(pshared); + *lock = 0; + return 0; +} + +int pthread_spin_destroy(pthread_spinlock_t *lock) { + UNUSED(lock); + return 0; +} + +int pthread_spin_lock(pthread_spinlock_t *lock) { + while (1) { + int i; + for (i=0; i < 10000; i++) { + if (__sync_bool_compare_and_swap(lock, 0, 1)) { + return 0; + } + } + sched_yield(); + } +} + +int pthread_spin_trylock(pthread_spinlock_t *lock) { + if (__sync_bool_compare_and_swap(lock, 0, 1)) { + return 0; + } + return EBUSY; +} + +int pthread_spin_unlock(pthread_spinlock_t *lock) { + __asm__ __volatile__ ("" ::: "memory"); + *lock = 0; + return 0; +} + diff --git a/src/pthread_spinlock.h b/src/pthread_spinlock.h new file mode 100644 index 00000000..0b19b908 --- /dev/null +++ b/src/pthread_spinlock.h @@ -0,0 +1,41 @@ +/* pthread spinklock macos implementation + * + * Copyright (c) 2019-2021, wei.kukey + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Redis nor the names of its contributors may be used + * to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef KCC_REDIS_PTHREAD_SPINLOCK_H +#define KCC_REDIS_PTHREAD_SPINLOCK_H + +typedef int pthread_spinlock_t; + +int pthread_spin_init(pthread_spinlock_t *lock, int pshared); +int pthread_spin_destroy(pthread_spinlock_t *lock); +int pthread_spin_lock(pthread_spinlock_t *lock); +int pthread_spin_trylock(pthread_spinlock_t *lock); +int pthread_spin_unlock(pthread_spinlock_t *lock); + +#endif //KCC_REDIS_PTHREAD_SPINLOCK_H diff --git a/src/redis_oplog.c b/src/redis_oplog.c index 442df629..66fefa48 100644 --- a/src/redis_oplog.c +++ b/src/redis_oplog.c @@ -348,8 +348,13 @@ void cronBgsave(void) { if (growth >= server.cron_bgsave_rewrite_perc || (server.maxmemory && (unsigned)server.aof_inc_from_last_cron_bgsave > server.maxmemory * server.cron_bgsave_rewrite_perc / 100)) { + #if defined(__APPLE__) + serverLog(LL_NOTICE,"Starting cron bgsave on %lld%% (%lld/%lld) aof growth", + growth, server.aof_inc_from_last_cron_bgsave, base); + #elif (defined(__linux__) && defined(__GLIBC__)) serverLog(LL_NOTICE,"Starting cron bgsave on %lld%% (%ld/%lld) aof growth", growth, server.aof_inc_from_last_cron_bgsave, base); + #endif rdbSaveInfo rsi, *rsiptr; rsiptr = rdbPopulateSaveInfo(&rsi); rdbSaveBackground(server.rdb_filename, rsiptr); @@ -521,8 +526,13 @@ long long getAofFirstOpid(char *filename) { if (!strcasecmp("opinfo", argv[0])) { redisOplogHeader *loaded_header = (redisOplogHeader *)argv[1]; long long tmp_opid = loaded_header->opid; + #if defined(__APPLE__) + serverLog(LL_VERBOSE, "getAofFirstOpid: parsed first opid %lld in %s", + loaded_header->opid, filename); + #elif (defined(__linux__) && defined(__GLIBC__)) serverLog(LL_VERBOSE, "getAofFirstOpid: parsed first opid %ld in %s", loaded_header->opid, filename); + #endif cleaningOfGetAofFirstOpid(argv, fp, argc); return tmp_opid; } else { @@ -1634,19 +1644,35 @@ int writeAndFlushTmpRdbIndex(FILE *fp_tmp_rdb_index, char *filename) { } if(server.aof_state != AOF_OFF) { + #if defined(__APPLE__) + if(fprintf(fp_tmp_rdb_index, "%s %s %lld %lld\n", \ + filename, server.aof_filename, \ + server.aof_current_size, + (server.next_opid < 1 ? 0 : server.next_opid)) < 0) + #elif (defined(__linux__) && defined(__GLIBC__)) if(fprintf(fp_tmp_rdb_index, "%s %s %ld %lld\n", \ filename, server.aof_filename, \ server.aof_current_size, - (server.next_opid < 1 ? 0 : server.next_opid)) < 0) { + (server.next_opid < 1 ? 0 : server.next_opid)) < 0) + #endif + { serverLog(LL_WARNING, "Writing %s error: %s", REDIS_RDB_INDEX_TMP_FILENAME, strerror(errno)); return C_ERR; } + #if defined(__APPLE__) + serverLog(LL_NOTICE, + "BGSAVE done, write rdb.index, rdb name: %s, aof name: %s, " + "aof offset: %lld, next opid: %lld", + filename, server.aof_filename, \ + server.aof_current_size, server.next_opid); + #elif (defined(__linux__) && defined(__GLIBC__)) serverLog(LL_NOTICE, "BGSAVE done, write rdb.index, rdb name: %s, aof name: %s, " "aof offset: %ld, next opid: %lld", filename, server.aof_filename, \ server.aof_current_size, server.next_opid); + #endif if (rdbSaveAppliedInfoToRdbIndex(fp_tmp_rdb_index) != C_OK) { return C_ERR; } @@ -1813,7 +1839,11 @@ sds catExtraReplInfo(sds info) { info = sdscatprintf(info, "aof_psyncing_state:%d\r\n" "aof_psync_reading_filename:%s\r\n" + #if defined(__APPLE__) + "aof_psync_reading_offset:%lld\r\n" + #elif (defined(__linux__) && defined(__GLIBC__)) "aof_psync_reading_offset:%ld\r\n" + #endif "next_opid:%lld\r\n" "second_replid_opid:%lld\r\n", (slaveCheckAofPsyncingState() == C_OK ? 1 : 0), @@ -2453,7 +2483,7 @@ void doSendAofToSlave(aeEventLoop *el, int fd, void *privdata, int mask) { /* Align IOBUF to multiple of 1024 */ const int IOBUF_LEN = PROTO_IOBUF_LEN; - char buf[IOBUF_LEN]; + char buf[PROTO_IOBUF_LEN]; ssize_t nwritten, buflen; lseek(aof_psync_reading_fd, slave->repldboff, SEEK_SET);