sequence

In this paper, importRDB of Claudb is studied

importRDB

Claudb 1.7.1 / SRC/main/Java/com/lot/tonivade/claudb/DBServerState Java

public class DBServerState { //...... public void importRDB(InputStream input) throws IOException { RDBInputStream rdb = new RDBInputStream(input); Map<Integer, Map<DatabaseKey, DatabaseValue>> load = rdb.parse(); for (Map.Entry<Integer, Map<DatabaseKey, DatabaseValue>> entry : load.entrySet()) { databases.get(entry.getKey()).overrideAll(ImmutableMap.from(entry.getValue())); }} / /... }Copy the code
  • The importRDB method creates the RDBInputStream, executes its parse method to parse it, and then loops through the result. Get (entry.getKey()).overrideall (ImmutableMap. From (entry.getValue())))

RDBInputStream

Claudb 1.7.1 / SRC/main/Java/com/lot/tonivade/claudb/personal/RDBInputStream. Java

public class RDBInputStream { private static final SafeString REDIS_PREAMBLE = safeString("REDIS"); private static final long TO_MILLIS = 1000L; private static final int HASH = 0x04; private static final int SORTED_SET = 0x03; private static final int SET = 0x02; private static final int LIST = 0x01; private static final int STRING = 0x00; private static final int TTL_MILLISECONDS = 0xFC; private static final int TTL_SECONDS = 0xFD; private static final int SELECT = 0xFE; private static final int END_OF_STREAM = 0xFF; private static final int REDIS_VERSION = 6; private static final int VERSION_LENGTH = 4; private static final int REDIS_LENGTH = 5; private final CheckedInputStream in; public RDBInputStream(InputStream in) { this.in = new CheckedInputStream(in, new CRC64()); } public Map<Integer, Map<DatabaseKey, DatabaseValue>> parse() throws IOException { Map<Integer, Map<DatabaseKey, DatabaseValue>> databases = new HashMap<>(); int version = version(); if (version > REDIS_VERSION) { throw new IOException("invalid version: " + version); } Long expireTime = null; HashMap<DatabaseKey, DatabaseValue> db = null; for (boolean end = false; ! end;) { int read = in.read(); switch (read) { case SELECT: db = new HashMap<>(); databases.put(readLength(), db); break; case TTL_SECONDS: expireTime = parseTimeSeconds(); break; case TTL_MILLISECONDS: expireTime = parseTimeMillis(); break; case STRING: ensure(db, readKey(), readString(expireTime)); expireTime = null; break; case LIST: ensure(db, readKey(), readList(expireTime)); expireTime = null; break; case SET: ensure(db, readKey(), readSet(expireTime)); expireTime = null; break; case SORTED_SET: ensure(db, readKey(), readSortedSet(expireTime)); expireTime = null; break; case HASH: ensure(db, readKey(), readHash(expireTime)); expireTime = null; break; case END_OF_STREAM: // end of stream end = true; db = null; expireTime = null; break; default: throw new IOException("not supported: " + read); } } verifyChecksum(); return databases; } private int version() throws IOException { SafeString redis = new SafeString(read(REDIS_LENGTH)); if (! redis.equals(REDIS_PREAMBLE)) { throw new IOException("not valid stream"); } return parseVersion(read(VERSION_LENGTH)); } private int parseVersion(byte[] version) { StringBuilder sb = new StringBuilder(); for (byte b : version) { sb.append((char) b); } return Integer.parseInt(sb.toString()); } private void verifyChecksum() throws IOException { long calculated = in.getChecksum().getValue(); long readed = parseChecksum(); if (calculated ! = readed) { throw new IOException("invalid checksum: " + readed); } } private long parseChecksum() throws IOException { return ByteUtils.byteArrayToLong(read(Long.BYTES)); } / /... }Copy the code
  • The constructor of RDBInputStream wraps InputStream using CheckedInputStream; The parse method first parses version for validation, then loops through in.read(), SELECT, TTL_SECONDS, TTL_MILLISECONDS, STRING, LIST, SET, SORTED_SET, HASH, END_OF_STREAM; Finally, run the verifyChecksum command to verifyChecksum

readKey

Claudb 1.7.1 / SRC/main/Java/com/lot/tonivade/claudb/personal/RDBInputStream. Java

private DatabaseKey readKey() throws IOException { return new DatabaseKey(readSafeString()); } private SafeString readSafeString() throws IOException { int length = readLength(); return new SafeString(read(length)); } private int readLength() throws IOException { int length = in.read(); if (length < 0x40) { // 1 byte: 00XXXXXX return length; } else if (length < 0x80) { // 2 bytes: 01XXXXXX XXXXXXXX int next = in.read(); return readLength(length, next); } else { // 5 bytes: 10...... XXXXXXXX XXXXXXXX XXXXXXXX XXXXXXXX return byteArrayToInt(read(Integer.BYTES)); } } private byte[] read(int size) throws IOException { byte[] array = new byte[size]; int read = in.read(array); if (read ! = size) { throw new IOException("error reading stream"); } return array; }Copy the code
  • The readKey method performs readSafeString, first readLength, then read according to length

readString

Claudb 1.7.1 / SRC/main/Java/com/lot/tonivade/claudb/personal/RDBInputStream. Java

private DatabaseValue readString(Long expireTime) throws IOException { return string(readSafeString()).expiredAt(expireTime ! = null ? ofEpochMilli(expireTime) : null); }Copy the code
  • The readString method reads SafeString first, then converts to DatabaseValue and sets expiredAt

readList

Claudb 1.7.1 / SRC/main/Java/com/lot/tonivade/claudb/personal/RDBInputStream. Java

private DatabaseValue readList(Long expireTime) throws IOException { int size = readLength(); List<SafeString> list = new LinkedList<>(); for (int i = 0; i < size; i++) { list.add(readSafeString()); } return list(list).expiredAt(expireTime ! = null ? ofEpochMilli(expireTime) : null); }Copy the code
  • The readList method reads the number of list elements by readLength, executes readSafeString one by one, converts the list to DatabaseValue, and sets expiredAt

readSet

Claudb 1.7.1 / SRC/main/Java/com/lot/tonivade/claudb/personal/RDBInputStream. Java

private DatabaseValue readSet(Long expireTime) throws IOException { int size = readLength(); Set<SafeString> set = new LinkedHashSet<>(); for (int i = 0; i < size; i++) { set.add(readSafeString()); } return set(set).expiredAt(expireTime ! = null ? ofEpochMilli(expireTime) : null); }Copy the code
  • The readSet method reads the number of set elements by readLength, executes readSafeString one by one, converts the set to DatabaseValue, and sets expiredAt

readSortedSet

Claudb 1.7.1 / SRC/main/Java/com/lot/tonivade/claudb/personal/RDBInputStream. Java

private DatabaseValue readSortedSet(Long expireTime) throws IOException { int size = readLength(); Set<Entry<Double, SafeString>> entries = new LinkedHashSet<>(); for (int i = 0; i < size; i++) { SafeString value = readSafeString(); Double score = readDouble(); entries.add(score(score, value)); } return zset(entries).expiredAt(expireTime ! = null ? ofEpochMilli(expireTime) : null); }Copy the code
  • The readSortedSet method reads the number of set elements by readLength, then adds readSafeString and readDouble to the LinkedHashSet. Finally, convert entries to DatabaseValue and set expiredAt; The difference with readSet is that score is read

readHash

private DatabaseValue readHash(Long expireTime) throws IOException { int size = readLength(); Set<Tuple2<SafeString, SafeString>> entries = new LinkedHashSet<>(); for (int i = 0; i < size; i++) { entries.add(entry(readSafeString(), readSafeString())); } return hash(entries).expiredAt(expireTime ! = null ? ofEpochMilli(expireTime) : null); }Copy the code
  • The readHash method first reads the number of hash elements by readLength, then executes readSafeString and readSafeString one by one, converting it into an entry and adding it to the LinkedHashSet. Finally, convert entries to DatabaseValue and set expiredAt

summary

The importRDB method creates the RDBInputStream, executes its parse method to parse it, and then loops through the result. Get (entry.getKey()).overrideall (ImmutableMap. From (entry.getValue())))

doc

  • DBServerState