SA服务框架——SA_Store存储服务信息

这篇文章我们来读samgr_endpoint/source/sa_store.c和sa_store.h

1. sa_store.h

首先从整个信息存储的结构体入手,再分析其对应的操作函数

1.1 SAStore

这是整个结构体的入口
在这里插入图片描述
里面包含了五项属性:

  • int saSize:保存了整个结构体的大小,每当要新加入内容时,会在这里更新其大小
  • ListNode * root:后续服务和feature的信息会存储在这个链表中
  • int16 mapSize:maps数组的大小
  • int16 mapTop:相当于指向数组的指针
  • PidHandle *maps:存储handle相关数据的结构

我们从ListNode结构体开始往下深入

1.2 ListNode

在这里插入图片描述
仅含两个属性:

  • ListNode * next:指向下一个结点的指针
  • ServiceInfo info:每个结点代表一个服务,info存储了该服务的信息

1.3 ServiceInfo

在这里插入图片描述
ServiceInfo三个属性:

  • char name[ ]:服务名称的存储数组
  • handle:服务处理函数的信息
  • FeatureNode *head:一个服务对应0个、1个或多个feature同样需要一个feature链表组织管理其信息

1.4 FeatureNode

在这里插入图片描述
feature结点上四个属性:
char name[ ]:feature的名称
uint32 isDefault:是否为默认
uint32 token:identity中的重要信息
FeatureNode *next:指向下一个结点的指针

1.5 PidHandle

maps的存储结构:
在这里插入图片描述
四个属性:

  • pid_t pid:用于查找的属性(关于权限的id)
  • uid_t uid:用于查找的属性(关于权限的id)
  • uint32 handle:samgr的handle类型编号
  • uint32 deadId:进行注销回调是留下的deadId

1.6 结构体展开图

这里简单的将结构体展开,便于读者更好的理解结构体之间的嵌套关系
在这里插入图片描述
看完结构我们看到其操作函数


2. sa_store.c

这里只挑选几个重要的函数进行详细讲解,其余的简单介绍下功能,留给读者自己研读

2.1 SASTORA_FindHandleByPid

第一个函数是在maps[ ]数组中根据给定的pid返回maps[ ]中一致pid所在的位置
在这里插入图片描述
里面应用了非常常见的查找方式:二分查找,复杂度为lg(N)——也间接说明了maps中各个结点按照pid的大小进行排序,在后面maps的save函数中也能看出插入的时候是按pid有序插入


下面涉及了两个存储函数,第一个是往maps中存储;另一个是往ListNode链表中存储

2.2 SASTORA_SaveHandleByPid

/*
函数功能:将给定的handle存入maps(不存在对应pid则新建,存在pid但内容不同则更新,pid和内容都相同则直接返回)
函数参数:saStore:存储的maps所在结构体;handle:需要存储的PidHandle:类型
函数返回:EC_SUCCESS:成功;EC_NOMEMORY:内存不足
*/
int SASTORA_SaveHandleByPid(SAStore *saStore, PidHandle handle)
{
    PidHandle saved = {.handle = INVALID_INDEX};
    //通过pid在maps中找到对应index
    int index = SASTORA_FindHandleByPid(saStore, handle.pid, &saved);
    //在这里判断是否相同,相同直接返回
    if (saved.handle == handle.handle) {
        return EC_SUCCESS;
    }
    //pid一致但handle不一致则更新handle
    if (index != INVALID_INDEX) {
        saStore->maps[index] = handle;
        return EC_SUCCESS;
    }
    //不存在则需要新添加
    //先更新maps的大小
    if (saStore->mapSize <= saStore->mapTop) {
        PidHandle *newMap = (PidHandle *)SAMGR_Malloc(sizeof(PidHandle) * (saStore->mapSize + GROW_STEP));
        if (newMap == NULL) {
            return EC_NOMEMORY;
        }

        if (saStore->maps != NULL) {
            (void)memcpy_s(newMap, sizeof(PidHandle) * (saStore->mapSize + GROW_STEP),
                           saStore->maps, sizeof(PidHandle) * saStore->mapSize);
        }
        PidHandle *oldMap = saStore->maps;
        saStore->maps = newMap;
        saStore->mapSize += GROW_STEP;
        //释放旧maps
        SAMGR_Free(oldMap);
    }
    int i;
    //实现插入排序 这里是按照pid从小到大的顺序进行排序
    //找到第一个比要插入pid小的结点
    for (i = saStore->mapTop - 1; i >= 0; --i) {
        if (saStore->maps[i].pid < handle.pid) {
            break;
        }
        //比其大的结点后移
        saStore->maps[i + 1] = saStore->maps[i];
    }
    //在其后面拆入handle
    saStore->maps[i + 1] = handle;
    ++(saStore->mapTop);
    return EC_SUCCESS;
}

函数流程:
1. 调用SASTORA_FindHandleByPid根据pid在原maps中查找是否存在该pid
2. 存在该pid且handle也相同,则无需更新直接返回
3. 存在相同pid但对应handle不同,则更新handle后返回
4. 不存在pid则需要新添加数据
5. 首先更新maps的大小(这里虽然是使用了数组但是数组的大小是根据数据的大小而定,所有要新添加数据需要先扩展数组大小)
6. 将旧数据拷贝到新maps中,释放oldmaps
7. 这里按照pid从小到大的顺序进行排序,所以从最后一个开始找到比新插入pid小的结点,比其大的结点往后移一位(插入排序的思路)
8. 将新pid添加在其后面

2.3 SASTORA_Save

该函数用于service和feature链表中结点的添加

/*
函数功能:将identity中的信息存入saStore中
函数参数:saStore:存储的结构体;service、feature:对应字符串;identity:需要存储的身份信息
函数返回:EC_INVALID:无效参数;EC_NOSPACE:结构已满;EC_NOMEMORY:内存已满;EC_SUCCESS:成功
*/
int SASTORA_Save(SAStore *saStore, const char *service, const char *feature, const SvcIdentity *identity)
{
    //检查传入参数是否为空
    if (saStore == NULL || service == NULL || identity == NULL) {
        return EC_INVALID;
    }

    //调用根据serviceName查找root结点下的serviceNode
    ListNode *curNode = FindServiceByName(saStore->root, service);
    //找到则获取其featureList的head结点
    FeatureNode *fNode = (curNode == NULL) ? NULL : curNode->info.head;
    //再通过featureName查找对应featureNode
    fNode = FindFeatureByName(fNode, feature);
    //存在直接返回不用存储
    if (fNode != NULL) {
        return EC_SUCCESS;
    }

    if (saStore->saSize >= MAX_SA_NUM) {
        return EC_NOSPACE;
    }

    fNode = SAMGR_Malloc(sizeof(FeatureNode));
    if (fNode == NULL) {
        return EC_NOMEMORY;
    }
    //给featureNode属性赋值
    fNode->token = identity->token;
    //由于给定的featureName可以为空,为空则说明为default
    fNode->isDefault = feature == NULL;
    fNode->name[0] = 0;
    //给定了featureName则存入name数组中
    if (feature != NULL) {
        if (strcpy_s(fNode->name, MAX_NAME_LEN, feature) != EOK) {
            SAMGR_Free(fNode);
            return EC_INVALID;
        }
    }
    //当serviceNode无法找到时
    if (curNode == NULL) {
        curNode = SAMGR_Malloc(sizeof(ListNode));
        if (curNode == NULL) {
            SAMGR_Free(fNode);
            return EC_NOMEMORY;
        }
        //进行serviceName的拷贝
        if (strcpy_s(curNode->info.name, MAX_NAME_LEN, service) != EOK) {
            SAMGR_Free(fNode);
            SAMGR_Free(curNode);
            return EC_INVALID;
        }
        //service结点的属性拷贝
        curNode->info.handle = identity->handle;
        curNode->info.head = NULL;
        //循环链表
        curNode->next = saStore->root;
        saStore->root = curNode;
    }
    //循环链表
    fNode->next = curNode->info.head;
    curNode->info.head = fNode;
    saStore->saSize++;
    return EC_SUCCESS;
}

函数流程如下:
1. 调用函数FindServiceByName返回对应的serviceNode
2. 如果该service存在feature链表则调用FindFeatureByName返回对应feature
3. 如果存在该feature则直接返回说明无需添加
4. 不存在则新建一个fNode将identity->token赋给其属性token,并将isDefault和name初始化
5. 如果参数传了featureName则拷贝入name属性中
6. 当调用FindServiceByName无法找到对应serviceNode,则创建一个新serviceNode并初始化
7. 将serviceNode上链
8. 将fNode上链

这里可以看到serviceList和featureList都是循环链表,头尾相连

2.4 其他

其他函数比较简单,这里仅做功能介绍,留给读者自行研读

  • SASTORA_FindHandleByUidPid:通过uid或pid一致来查询对应maps数据——同样用到了二分查找
  • SASTORA_FindPidHandleByIpcHandle:通过给定的handle在maps找到handle一致的pidHandle
  • SASTORA_Find:调用FindServiceByName和FindFeatureByName获取service的handle和feature的token存入identity中并返回
  • SASTORA_ClearByPid:通过pid清除maps和serviceList中对应数据
  • SASTORA_ClearServiceByHandle:通过handle查找serviceList上一致handle的结点删除
  • FreeTreeNode:释放链表结点

3. 总结

saStore主要存储了service和feature相关的信息数据(包括service的handle和feature的token等),数据结构为循环链表,通过pid可以唯一定位一个service和maps中的一项数据体,在功能函数中使用了插入排序根据pid的大小对maps的数据项进行排序,使用二分查找对maps中数据项进行查找

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

国家一级假勤奋研究牲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值