mysee:MYSEE:Sp数据结构分析初稿

以前写了MYSEE 服务器端源码分析文档,主要是对其中的消息机制(sp,cp,ts,之间的交互)的分析。因为CU抽风,发表的文章无故给我删除了 ,所以这个不是完整的             

 

 

             Sp 数据结构分析(初稿)

一:准备工作

       1 )熟悉 /opt/mysee/data/sp/ 目录下面有哪些目录( channel   data  playlist  program )

2 )在目录 program 中有三个文件( 0    config     keysample )

3 )知道一个 channel 到底是什么,里面包含什么东西?

这个问题困扰了我很久。

我现在的理解是这样的,在 program 中包含有很多目录,比如 /opt/mysee/data/sp/program/29bea7e94db8359982f1976e40cd780b , 都是 32 位的 16 进制数。 里面包含了 3 个文件( 0    config     keysample )。 这个里面的文件是管理员上传的。在 sp 目录下面还有一个目录 channel 。说到这里,我说说一部电影是怎么传上去的(举例) 首先用格式转换工具将 .avi 等视频文件转换成为一个目录文件 29bea7e94db8359982f1976e40cd780b ,里面当然包含三个文件( 0    config     keysample ) ,管理员将这个目录上传到 /opt/mysee/data/sp/program 中,这个是第一步。在系统初始化的时候,系统会打开 program 目录,然后依次检查下面的文件(比如 29bea7e94db8359982f1976e40cd780b )是否在 programhash 列表中,如果不在其中,我们就调用 callo 函数生成一个 channel 数据结构,赋值(没有对 channel 结构中的 media 指针赋值),然后添加到 programhash 列表。再对 channel 中的 media 指针赋值,添加到 channelhash 当中。

 

说说 media 是怎么赋值的,这个指针是指向 config 文件里面的一个数据字段 data 的

Config 文件内容如下:

BitRate=34.705500

BlockSize=16384

ChannelName=[2008.08.03] 军鸡 +shamo.2007

ResourceHash=29bea7e94db8359982f1976e40cd780b

DataLength=220

Data =vids^@^@^P^@<80>^@^@ª^@8<9b>qVP70^@^@^P^@<80>^@^@ª^@8<9b>q<80><9f>X^EVÃÃ^A^@ª^@UYZ^A^@^@^@Â^B^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@;]^F^@^@^@^@^@(^@^@^@^@^B^@^@<80>^A^@^@^A^@^L^@VP70^@^P^F^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@^@auds^@^@^P^@<80>^@^@ª^@8<9b>q1^@^@^@^@^@^P^<80>^@^@ª^@8<9b>q<81><9f>X^EVÃÎ^Q¿^A^@ª^@UYZA^@^@^@¡^@^@^@1^@^A^@D¬^@^@ý^@^@^B^@@^A

Programhash 和 channelhash 有什么区别? 为什么要分成两个 hash ,这两 hash 表又是怎么联系起来的?

  用 hash 肯定是为了提高查询效率,我理解是在 channel 结构体中有一个 int  ref 成员,它是一个 channel 的引用数, 当引用数 ref < 0 时,我们将改它从 programhash 表里面删除。

两个表的区别:

       /opt/mysee/data/sp/program 目录中的文件是一直存在的,

/opt/mysee/data/sp/channel  目录中的文件是在打开节目是时候生成的,并且在改节目关闭后一定时间内是会删除的,这个在代码中是可以看见的。

上面这些我觉得就是要拥有两个 hash 表的原因,至于两者是怎么联系的。 (比如当在 channelhash 中删除一个 channel 时,对 programhash 中的相应的 channel 的应用数( ref )要减一)这个在下面具体数据结构中再分析

说了这么多废话其实是为了更好的理解下面的数据结构中成员的意思 :-D

 

二:具体数据结构分析    

struct LiveChannelInfo

{

       unsigned int maxID;  // 这个 channel 全部文件中最大的 id  可以通过 newPListChannelFile 这个函数看出来

       struct Session *dataSource;    // source of data, a connection to SP or uplevel CP

       unsigned int total;

       struct SPUpdate s;

       unsigned int max_queue; //pcinfo->max_queue = BLOCK_PER_FILE;  这个应该是每个文件所拥有的最大块的数目,要注意它和每一块多大的区别

       float bitrate; // 码率

//     struct BlockData *blocks;

       int max_channel; // 有多少个频道

       int cur_channel; // 当前 channel 数目

       struct MediaData *media;

       int isSave;//guess : issave = 1 represent  save the channel (这个是在关闭 channel 的时候用的)

 

#ifdef __CP_SOURCE

       char *bitflag;                // for CP, it is pending status, for SP, it is keysample status

       unsigned char *indisk;

       unsigned int numofsp;

       struct NormalAddress SPLIST[256];

#endif

 

#ifdef __SP_SOURCE

       unsigned int startid;

       struct MList *mlist; // 指向频道链表

       /*

for the dir of /data/sp/program/ , there are three files . now we watch out the file 0,

input pointer point to this file .  they may have more than just one file . but not  beyond the numb of MAX_FILEINPUT .

in this project , we reality it just have only one file   "0"

       */

       FILE *input [MAX_FILEINPUT]; // 一个 channel 拥有的文件名列表

       FILE *keyfile;// 这个指向我们每一个文件下面的那个 keysample 文件

       unsigned int numinput;  //the number of files one channel contains

       unsigned int numblocks;

       unsigned int userid;

       float limitedBitRate;

       unsigned int status;  // 1 meaning  this channel has been closed     

       time_t updated; // channel update time

#endif

};

注意:在这个数据结构中没有对 media 这个指针的操作

      Input 指针也是重点要注意的

首先要注意的是 input 和 m_lists 的指针类型,一个是 file *  , 一个是 channel *

两者都相当于二重指针, input 指向( 0    config     keysample )   0 这个文件 ,这里说说代码中为什么要用二重指针,这里只有一个文件( 0 这个文件),用一重的也可以呀! 代码实现中规定一个 channel 里面最多可以有 max_fileinput 这么多个文件,但是在我们的具体实现中只是生成了一个 文件 0 (你喜欢也可多生成一些,比如 1 , 2 文件等)。 这里的指针 m_lists 就是连接 channelhash 和 programhash 的指针。

 

----------------------------------------------------------------------------------------------------------------------

struct Channel

{

       int type;

       int ref ;  // 某个节目的引用数 ( 也可以说频道的引用数 )

       char fname[CHNLURL_LEN]; //filename 这个是通过 buildProgPath 这个函数生成的

       char channel_name[CHNLURL_LEN];// 频道名

       char channel_md5[MD5_LEN+1];  // 频道名 md5 码

       int maxblocksize;// 从 config 文件中读取的 blocksize 大小 ( 每块的大小 ), 注意与 datalenght 的区别

       int numclient; //

       int numjob;                                        // number of jobs

       unsigned int ctime;

#ifdef __SP_SOURCE

       int numofnp[MAX_TS];

#endif

#ifdef __CP_SOURCE

       time_t last_nearpeer;

#endif

       long long downsize;       // recv from SP for CP, file size for SP;

       long long upsize;    // send to NP

       FILE *db;

       struct LiveChannelInfo *pcinfo;

       struct Edge *PeerHead;   //channel list head  

       struct Channel *next;// 具有相同 id 的 channel 的链接

       struct Channel *lnext; // 全部 channel 的链接

};

注意:最后三个指针

struct Session

{

       int type;

       int socket;// 由 handle_new_connection 这个函数赋值

#ifdef __CP_SOURCE

       unsigned char npcp;              //TYPE_CP

       unsigned char flag;

       unsigned short first;

       unsigned int sock_flag;         /* saved for restore after connection succed */

       float version;  //np 的版本号,这个是从 message 的开头 的内存中读取出来的。

       long long totalup;

       struct PeerInfoWithAddr addr;

//     struct CorePeerInfo *c;

//     struct TransferInfo *t;

#endif

/*

at first ,we know that  session present a client connect to sp .so the host and port is the value of the client (cp)

watch out the  type of this two value

*/

       unsigned int host;

       unsigned int port;

       unsigned int time_sec;    //time of creation

       unsigned int last_transferblock;     //time of last send or recv a block

// 这里就很清楚了, off 其实就是 message 的长度

// buf+start 是 message 指针指向的地方

       char *buf;

       unsigned int start;

       unsigned int off; 

       unsigned int numjob;

       struct JobDes *head;

       struct Channel *pc;// difficult point ( 在一个 session 中包含这个元素有什么作用 ?

       struct Edge *header;

       // 每个 session 通过 Edge 中的 enext 也串成一个链表。

       // 这个链表的头是 session 结构中的 header 指针

       struct Session *next;

};

struct Edge

{

       struct Channel *head;

       struct Session *me;

       struct Edge *cnext;

       struct Edge *enext;

};

最后说说 edge

Session:  D,E

Channel  A,B,C

Edge : P 等

对于 edge p ,对应 channel A 和 Session D 。举例分析

当我们要删除边 p 的时候

对与 channelA ,通过单向链表表头 PeerHead 来寻找所有连接到 A 上面的 edge ,如果表头第一个指向的边不是 p ,通过第一条边的 cnext 指针寻找下一条边。 直到找到或为 null 为止,然后删除改边

对于 Session D,通过单向链表表头 header 来寻找所以连接到改 Session 的所以边,如果表头第一个指向的边不是 p ,通过第一条边的 enext 指针寻找下一条边。 直到找到或为 null 为止然后删除改边

 

            

这是只是我的笔记,欢迎讨论 ^_^

 

相关推荐

相关文章