SDS, short for Simple Dynamic Strings, is a string type defined by Redis.
typedef char *sds;
Copy the code
Redis is just a string array with Simple Dynamic Strings. Yes, I thought so at that time, but after reading the source code carefully, I found that SDS is not fighting alone, it also has comrades SDSHDR, SDSHDR is a quintuplet, they are SDSHDR5, SDSHDR8, SDSHD16, SDSHDR32, SDSHD64. From small to big.
SDSHDR stands for Simple Dynamic Strings Header
/* The old five (sdshdr5) is never used because they are not the same as others */
struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* The lower three bits represent the type, and the higher five bits represent the length of the string */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* The length of the string */
uint8_t alloc; /* Allocate the length */
unsigned char flags; /* The lower three bits indicate the type, and the higher five bits are not used */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* The length of the string */
uint16_t alloc; /* Allocate the length */
unsigned char flags; /* The lower three bits indicate the type, and the higher five bits are not used */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* The length of the string */
uint32_t alloc; /* Allocate the length */
unsigned char flags; /* The lower three bits indicate the type, and the higher five bits are not used */
char buf[];
};
struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* The length of the string */
uint64_t alloc; /* Allocate the length */
unsigned char flags; /* The lower three bits indicate the type, and the higher five bits are not used */
char buf[];
};
Copy the code
Knowledge! This is the key! __attribute__ ((__packed__)) you’ll see the following code in a moment: (s)-(sizeof(struct sdshdr##T))), s[-1], (char*) s-sdshdrsize (s[-1]))
This command is used to disable memory alignment at compile time.
So, the structure in memory looks like this:
Look like this, before those coquettish walk position is very clear.
// s minus SDSHDR length = pointer to the SDSHDR structure(s) - (sizeof (struct sdshdr# # T))),// s previous position = flags
s[-1]
// Has the same effect as 1
(char*)s-sdsHdrSize(s[-1])
Copy the code
With that in mind, it’s easy enough to look at the code in SDS.c and SDS.h. Let’s focus on two functions
- Create SDS string
sds sdsnewlen(const void *init, size_t initlen) {
void *sh;
sds s;
/* Determines the type of SDS based on the length of the string */
char type = sdsReqType(initlen);
/* The fifth is discriminated against */
if (type == SDS_TYPE_5 && initlen == 0) type = SDS_TYPE_8;
/* Calculate the length of sdsHeader */
int hdrlen = sdsHdrSize(type);
/* flags */
unsigned char *fp;
/* Open up memory space, +1 is to put a last \0, compatible with traditional C language, when in Rome, do as the Romans do */
sh = s_malloc(hdrlen+initlen+1);
if(! init) memset(sh,0, hdrlen+initlen+1);
if (sh == NULL) return NULL;
/* This bit points to the beginning of the string */
s = (char*)sh+hdrlen;
/* This bit goes to flags */
fp = ((unsigned char*)s)-1;
/* Initializes sdsHeader */ depending on the type
switch(type) {
case SDS_TYPE_5: {
*fp = type | (initlen << SDS_TYPE_BITS);
break;
}
case SDS_TYPE_8: {
SDS_HDR_VAR(8,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
break;
}
case SDS_TYPE_16: {
SDS_HDR_VAR(16,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
break;
}
case SDS_TYPE_32: {
SDS_HDR_VAR(32,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
break;
}
case SDS_TYPE_64: {
SDS_HDR_VAR(64,s);
sh->len = initlen;
sh->alloc = initlen;
*fp = type;
break; }}/* String assignment */
if (initlen && init)
memcpy(s, init, initlen);
s[initlen] = '\ 0';
return s;
}
Copy the code
- Dynamically expand SDS space
sds sdsMakeRoomFor(sds s, size_t addlen) {
void *sh, *newsh;
/* avail = alloc-len */
size_t avail = sdsavail(s);
size_t len, newlen;
char type, oldtype = s[-1] & SDS_TYPE_MASK;
int hdrlen;
/* If there is enough space left, there is no need to expand */
if (avail >= addlen) return s;
len = sdslen(s);
sh = (char*)s-sdsHdrSize(oldtype);
newlen = (len+addlen);
/* Redis believes that once the string has been expanded, it has a high chance of being expanded again, so it will add more space to it to prevent frequent expansion */
if (newlen < SDS_MAX_PREALLOC)
newlen *= 2;
else
newlen += SDS_MAX_PREALLOC;
/* recalculate type */
type = sdsReqType(newlen);
/* The fifth is discriminated against again */
if (type == SDS_TYPE_5) type = SDS_TYPE_8;
hdrlen = sdsHdrSize(type);
if (oldtype==type) {
/* When the original type is the same as the new type, the original base is realloc space */
newsh = s_realloc(sh, hdrlen+newlen+1);
if (newsh == NULL) return NULL;
s = (char*)newsh+hdrlen;
} else {
/* Otherwise you need to re-malloc the entire space and copy */
newsh = s_malloc(hdrlen+newlen+1);
if (newsh == NULL) return NULL;
memcpy((char*)newsh+hdrlen, s, len+1);
s_free(sh);
s = (char*)newsh+hdrlen;
s[-1] = type;
sdssetlen(s, len);
}
sdssetalloc(s, newlen);
return s;
}
Copy the code
Concern public number: Java baodian