zoukankan      html  css  js  c++  java
  • Android native CursorWindow数据保存原理

    我们通过Uri查询数据库所得到的数据集,保存在native层的CursorWindow中。CursorWindow的实质是共享内存的抽象,以实现跨进程数据共享。共享内存所採用的实现方式是文件映射。

    在ContentProvider端透过SQLiteDatabase的封装查询到的数据集保存在CursorWindow所指向的共享内存中。然后通过Binder把这片共享内存传递到ContentResolver端,即查询端。

    这样客户就能够通过Cursor来訪问这块共享内存中的数据集了。

    那么CursorWindow是怎样实现的呢?

    1.通过Create静态函数来创建

    status_t CursorWindow::create(const String8& name, size_t size, CursorWindow** outCursorWindow) {
        String8 ashmemName("CursorWindow: ");
        ashmemName.append(name);//文件名称
    
        status_t result;
        int ashmemFd = ashmem_create_region(ashmemName.string(), size);
        if (ashmemFd < 0) {
            result = -errno;
        } else {
            result = ashmem_set_prot_region(ashmemFd, PROT_READ | PROT_WRITE);
            if (result >= 0) {
                void* data = ::mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, ashmemFd, 0);//文件映射
                if (data == MAP_FAILED) {
                    result = -errno;
                } else {
                    result = ashmem_set_prot_region(ashmemFd, PROT_READ);
                    if (result >= 0) {
                        CursorWindow* window = new CursorWindow(name, ashmemFd,
                                data, size, false /*readOnly*/);
                        result = window->clear();
                        if (!result) {
                            LOG_WINDOW("Created new CursorWindow: freeOffset=%d, "
                                    "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                                    window->mHeader->freeOffset,
                                    window->mHeader->numRows,
                                    window->mHeader->numColumns,
                                    window->mSize, window->mData);
                            *outCursorWindow = window;
                            return OK;
                        }
                        delete window;
                    }
                }
                ::munmap(data, size);
            }
            ::close(ashmemFd);
        }
        *outCursorWindow = NULL;
        return result;
    }

    2.通过文件句柄来创建。这样的case应该是在client的创建出一个CursorWindow所採用。

    status_t CursorWindow::createFromParcel(Parcel* parcel, CursorWindow** outCursorWindow) {
        String8 name = parcel->readString8();
    
        status_t result;
        int ashmemFd = parcel->readFileDescriptor();
        if (ashmemFd == int(BAD_TYPE)) {
            result = BAD_TYPE;
        } else {
            ssize_t size = ashmem_get_size_region(ashmemFd);
            if (size < 0) {
                result = UNKNOWN_ERROR;
            } else {
                int dupAshmemFd = ::dup(ashmemFd);
                if (dupAshmemFd < 0) {
                    result = -errno;
                } else {
                    void* data = ::mmap(NULL, size, PROT_READ, MAP_SHARED, dupAshmemFd, 0);
                    if (data == MAP_FAILED) {
                        result = -errno;
                    } else {
                        CursorWindow* window = new CursorWindow(name, dupAshmemFd,
                                data, size, true /*readOnly*/);
                        LOG_WINDOW("Created CursorWindow from parcel: freeOffset=%d, "
                                "numRows=%d, numColumns=%d, mSize=%d, mData=%p",
                                window->mHeader->freeOffset,
                                window->mHeader->numRows,
                                window->mHeader->numColumns,
                                window->mSize, window->mData);
                        *outCursorWindow = window;
                        return OK;
                    }
                    ::close(dupAshmemFd);
                }
            }
        }
        *outCursorWindow = NULL;
        return result;
    }

    CursorWindow是怎样保存查询到的数据集的呢?

    原理图例如以下:

    没一行所相应的数据採用FieldSlot数组来表示。

    图中黄色部分表示一行所相应的数据。假设列所相应的数据是long或者double。那么就直接保存在FieldSlot中,假设是Blob或者String,那么就在FieldSlot中保存数据的廉价量。

    FiledSlot的定义例如以下:

        struct FieldSlot {
        private:
            int32_t type;//列所相应的数据的类型
            union {
                double d;
                int64_t l;
                struct {
                    uint32_t offset;
                    uint32_t size;
                } buffer;
            } data;//data的数据类型是union,当type所表示的是String或者Blob的时候。offset表示的就是保存真实数据的buffer的偏移量。size表示buffer的大小
    
            friend class CursorWindow;
        } __attribute((packed));



  • 相关阅读:
    【BZOJ1345】[Baltic2007] 序列问题(单调栈大水题)
    【BZOJ2940】[POI2000] 条纹(Multi-SG)
    【BZOJ4589】Hard Nim(FWT+快速幂)
    【CF438E】The Child and Binary Tree(生成函数+多项式开根)
    【洛谷5205】【模板】多项式开根
    【BZOJ4036】[HAOI2015] 按位或(Min-Max容斥+FWT)
    【BZOJ4381】[POI2015] ODW(设阈值+倍增)
    【BZOJ3328】PYXFIB(矩乘+单位根反演)
    【BZOJ2674】Attack(整体二分+树状数组套线段树)
    单纯看懂公式的单位根反演
  • 原文地址:https://www.cnblogs.com/zhchoutai/p/6978964.html
Copyright © 2011-2022 走看看