franciscochonge 发表于 2021-11-16 09:13

MMKV的原理与实现二

一.MMKV.java


public class MMKV {

static {

    System.loadLibrary("mmkv");

}

private static String rootDir;

private final long nativeHandle;

public MMKV(long handle) {

    nativeHandle = handle;

}

public static String initialize(Context context) {

    String rootDir = context.getFilesDir().getAbsolutePath() + "/mmkv";

    return initialize(rootDir);

}

public static String initialize(String rootDir) {

    MMKV.rootDir = rootDir;

    jniInitialize(MMKV.rootDir);

    return rootDir;

}

public static MMKV defaultMMKV() {

    if (rootDir == null) {

      throw new IllegalStateException("You should Call MMKV.initialize() first.");

    }

    long handle = getDefaultMMKV();

    return new MMKV(handle);

}

public int getInt(String key, int defaultValue) {

    return getInt(nativeHandle, key, defaultValue);

}

public void putInt(String key, int value) {

    putInt(nativeHandle, key, value);

}

private static native void jniInitialize(String rootDir);

private static native long getDefaultMMKV();

private static native int getInt(long nativeHandle, String key, int defaultValue);

private static native void putInt(long nativeHandle, String key, int value);

}
二.MainActivity.java



public class MainActivity extends AppCompatActivity {

private static final String TAG = "MainActivity";

@Override

protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_main);

//    MMKV.initialize(this);

    MMKV.initialize("/sdcard/mmkv");

    MMKV mmkv = MMKV.defaultMMKV();

    Log.e(TAG, "a=" + mmkv.getInt("a", 0));

    Log.e(TAG, "b=" + mmkv.getInt("b", 0));

    Log.e(TAG, "c=" + mmkv.getInt("c", 0));

    Log.e(TAG, "d=" + mmkv.getInt("d", 0));

    mmkv.putInt("a", 1);

    mmkv.putInt("b", -1);

    mmkv.putInt("c", 128);

    mmkv.putInt("d", -128);

    Log.e(TAG, "a=" + mmkv.getInt("a", 0));

    Log.e(TAG, "b=" + mmkv.getInt("b", 0));

    Log.e(TAG, "c=" + mmkv.getInt("c", 0));

    Log.e(TAG, "d=" + mmkv.getInt("d", 0));

}

}

三.MMKV.cpp


#include "MMKV.h"

#include "MMKVLog.h"

#include "PBUtility.h"

#include <string>

#include <sys/stat.h>

#include <fcntl.h>

#include <unistd.h>

#include <sys/mman.h>

static unordered_map<string, MMKV *> *g_instanceDic = 0;

static string g_rootDir;

//默认的mmkv文件

#define DEFAULT_MMAP_ID "mmkv.default"

//系统给我们提供真正的内存时,用页为单位提供

//内存分页大小 一分页的大小

const int DEFAULT_MMAP_SIZE = getpagesize();

const int32_t Fixed32Size = 4;

void MMKV::initializeMMKV(const char *path) {

g_instanceDic = new unordered_map<string, MMKV *>;

g_rootDir = path;

//创建目录

mkdir(g_rootDir.c_str(), 0777);

}

MMKV *MMKV::defaultMMKV() {

return mmkvWithID(DEFAULT_MMAP_ID);

}

MMKV *MMKV::mmkvWithID(const string &mmapID) {

auto itr = g_instanceDic->find(mmapID);

if (itr != g_instanceDic->end()) {

    MMKV *kv = itr->second;

    return kv;

}

//创并放入集合

auto kv = new MMKV(mmapID);

(*g_instanceDic) = kv;

return kv;

}

MMKV::MMKV(const string &mmapID) :m_mmapID(mmapID), m_path(g_rootDir + "/" + mmapID) {

loadFromFile();

}

MMKV::~MMKV() {

delete m_output;

m_output = 0;

munmap(m_ptr, m_size);

m_ptr = 0;

::close(m_fd);

auto iter = m_dic.begin();

while (iter != m_dic.end()) {

    delete iter->second;

    iter = m_dic.erase(iter);

}

}

//todo 不再使用,请调用close方法(自己编写jni方法,通过jni调用)

void MMKV::close() {

auto itr = g_instanceDic->find(m_mmapID);

if (itr != g_instanceDic->end()) {

    g_instanceDic->erase(itr);

}

delete this;

}

void MMKV::loadFromFile() {

m_fd = open(m_path.c_str(), O_RDWR | O_CREAT, S_IRWXU);

if (m_fd < 0) {

    //打開失敗

    LOGI("打开文件:%s 失败!", m_path.c_str());

}

//读取文件大小

struct stat st = {0};

if (fstat(m_fd, &st) != -1) {

    m_size = st.st_size;

}

LOGI("打开文件:%s [%d]", m_path.c_str(), m_size);

/**

   * 健壮性。 文件是否已存在,容量是否满足页大小倍数

   */

m_ptr = static_cast<int8_t *>(mmap(0, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0));

//文件头4个字节写了数据有效区长度

memcpy(&m_actualSize, m_ptr, Fixed32Size);

bool loadFromFile = false;

//有数据

if (m_actualSize > 0) {

    //数据长度有效:不能比文件还大

    if (m_actualSize + Fixed32Size <= m_size) {

      loadFromFile = true;

    }

    //其他情况,MMKV是交给用户选择

    // 1、OnErrorDiscard 忽略错误,MMKV会忽略文件中原来的内容

    // 2、OnErrorRecover 还原,MMKV尝试按照自己的方式解析文件,并修正长度

}

/**

   * 解析 mmkv 文件中的数据 保存到 map集合中

   */

if (loadFromFile) {

    // 封装的protobuf解析器

    InputBuffer inputBuffer(m_ptr + Fixed32Size, m_actualSize);

    while (!inputBuffer.isAtEnd()) {

      //

      string key = inputBuffer.readString();

      if (key.length() > 0) {

      //读取value(包含value长度+value数据)

      InputBuffer *value = inputBuffer.readData();

//      unordered_map<string,InputBuffer*>::iterator iter;

      auto iter = m_dic.find(key);

      // 集合中找到了老数据

      if (iter != m_dic.end()){

          //清理老数据

          delete iter->second;

          // java-> map.remove

          m_dic.erase(key);

      }

      //本次数据有效,加入集合

      if (value && value->length() > 0) {

          // java-> map.insert

          m_dic.emplace(key, value);

      }

      }

    }

    //创建输出

    m_output = new OutputBuffer(m_ptr + Fixed32Size + m_actualSize,

                m_size - Fixed32Size - m_actualSize);

} else{

    //todo 文件有问题,忽略文件已存在的数据

}

}

int32_t MMKV::getInt(const char *key, int defaultValue) {

auto itr = m_dic.find(key);

// 找到了

if (itr != m_dic.end()) {

    // 获得value-> 解码器

    InputBuffer *buf = itr->second;

    int32_t returnValue = buf->readInt32();

    //多次读取,将position还原为0

    buf->restore();

    return returnValue;

}

return defaultValue;

}

void MMKV::putInt(const char *key, int value) {

size_t size = computeInt32Size(value);

//编码value

auto *buffer = new InputBuffer(size);

// 编码!

OutputBuffer buf(buffer->data(),buffer->length());

buf.writeInt32(value);

//记录到内存

auto itr = m_dic.find(key);

if (itr != m_dic.end()) {

    delete itr->second;

}

m_dic = buffer;

//同步到映射区(文件)

appendDataWithKey(key, buffer);

}

void MMKV::appendDataWithKey(string key, InputBuffer *value) {

//计算保存这个key-value需要多少字节

size_t itemSize = computeItemSize(key, value);

// 空闲空间不够了

if (itemSize > m_output->spaceLeft()){

    // 计算去重key后的数据 所需的存储空间

    size_t needSize = computeMapSize(m_dic);

    needSize += Fixed32Size; //总长度 4字节

    //小于文件大小

    if (needSize >= m_size){

      int32_t oldSize = m_size;

      do {

      //扩充一倍 为什么??? mmap规则限制:整数倍

      m_size *= 2;

      } while (needSize >= m_size);

      //重新设定文件大小

      ftruncate(m_fd, m_size);

      //解除映射

      munmap(m_ptr, oldSize);

      //重新映射

      m_ptr = (int8_t *) mmap(m_ptr, m_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_fd, 0);

    }

    //全量更新

    writeAcutalSize(needSize - Fixed32Size);

    delete m_output;

    //创建输出

    m_output = new OutputBuffer(m_ptr + Fixed32Size,

                m_size - Fixed32Size);

    //把map写入文件

    auto iter = m_dic.begin();

    for (; iter != m_dic.end(); iter++) {

      auto k = iter->first;

      auto v = iter->second;

      m_output->writeString(k);

      m_output->writeData(v);

    }

} else{

    //增量更新

    writeAcutalSize(m_actualSize + itemSize);

    //写入key

    m_output->writeString(key);

    //写入value

    m_output->writeData(value);

}

}

void MMKV::writeAcutalSize(size_t size) {

memcpy(m_ptr, &size, Fixed32Size);

m_actualSize = size;

}
四.InputBuffer.cpp


#include "InputBuffer.h"

InputBuffer::InputBuffer(size_t size) {

m_size = size;

m_position = 0;

isCopy = true;

if (size > 0) {

    m_buf = static_cast<int8_t *>(malloc(size));

}

}

InputBuffer::InputBuffer(int8_t *buf, size_t size) {

m_size = size;

m_position = 0;

m_buf = buf;

isCopy = false;

}

InputBuffer::~InputBuffer() {

if (isCopy && m_buf){

    free(m_buf);

}

m_buf = 0;

}

int8_t InputBuffer::readByte() {

//不能越界

if (m_position == m_size) {

    return 0;

}

return m_buf;

}

std::string InputBuffer::readString() {

//mmkv保存字符串:字符串长度+字符串

int32_t size = readInt32();

//剩下的数据有这么多

if (size <= (m_size - m_position) && size > 0) {

    std::string result((char *) m_buf + m_position, size);

    m_position += size; //读走了 size个了

    return result;

}

return "";

}

int32_t InputBuffer::readInt32() {

return 0;

}

int32_t InputBuffer::readInt64() {

//最高位为1

int8_t i = readByte();

//i < 0

// i & 0x80 == 0

//readByte();

//readByte();

// 0

//取低7位 i& 0x7f

int tmp = 0;

// tmp |= newTemp <<7;

return 0;

}

InputBuffer *InputBuffer::readData() {

//获得数据长度

int32_t size = readInt32();

//有效

if (size <= m_size - m_position && size > 0) {

    InputBuffer *data = new InputBuffer(m_buf + m_position, size);

    m_position += size;

    return data;

}

return 0;

}

void InputBuffer:restore() {

m_position = 0;

}

float InputBuffer::readFloat() {

int8_t b1 = readByte();

int8_t b2 = readByte();

int8_t b3 = readByte();

int8_t b4 = readByte();

int32_t value =

      (((int32_t) b1 & 0xff)) | (((int32_t) b2 & 0xff) << 8) | (((int32_t) b3 & 0xff) << 16) |

      (((int32_t) b4 & 0xff) << 24);

float returnValue = *(float *) &value;

return returnValue;

}

五.OutputBuffer.cpp

#include "OutputBuffer.h"

OutputBuffer::OutputBuffer(int8_t *buf, size_t size) {

m_position = 0;

m_size = size;

m_buf = buf;

}

OutputBuffer::~OutputBuffer() {

m_buf = 0;

}

void OutputBuffer::writeByte(int8_t value) {

if (m_position == m_size) {

    //满啦,出错啦

    return;

}

//将byte放入数组

m_buf = value;

}

void OutputBuffer::writeInt32(int32_t value) {

if (value < 0) {

    writeInt64(value);

} else {

    while (true){

      if (value <= 0x7f){

      writeByte(value);

      break;

      } else{

      // 取低7位,再最高位赋1

      writeByte(value & 0x7f | 0x80);

      value >>= 7;

      }

    }

}

}

void OutputBuffer::writeInt64(int64_t value) {

uint64_t i = value;

while (true){

    if (i & ~0x7f == 0){

      writeByte(i);

      break;

    } else{

      // 取低7位,再最高位赋1

      writeByte(i & 0x7f | 0x80);

      i >>= 7;

    }

}

}

void OutputBuffer::writeFloat(float value) {

//float 4字节 转为int32处理

//共用体或者指针修改

#if 0

union Converter{

    int32_t first;

    float sencond;

};

Converter converter;

converter.sencond = value;

int32_t i = converter.first;

#else

int32_t i = *(int32_t *) &value;

#endif

//取低8位写入

writeByte((i) & 0xff);

writeByte((i >> 8) & 0xff);

writeByte((i >> 16) & 0xff);

writeByte((i >> 24) & 0xff);

}

void OutputBuffer::writeString(std::string value) {

//写入长度

size_t numberOfBytes = value.size();

writeInt32(numberOfBytes);

//写入数据

memcpy(m_buf + m_position, value.data(), numberOfBytes);

m_position += numberOfBytes;

}

void OutputBuffer::writeData(InputBuffer *value) {

//长度

writeInt32(value->length());

//数据

size_t numberOfBytes = value->length();

memcpy(m_buf + m_position, value->data(), numberOfBytes);

m_position += numberOfBytes;

}
页: [1]
查看完整版本: MMKV的原理与实现二