(一)前序
以C++语言编写haoJson类库,构建通用的网络服务程序框架haoFrame。从此出发,设计和实现了haoQueue队列中间件。
详见csdn : https://blog.csdn.net/u011697262/article/details/105868979
全部代码开源,可以在以下svn进行下载:
svn://www.uralice.com/alice/share/haoC++
账号:guest
密码:123456
1
2
3
如有优化建议或发现bug,请发邮件给 jim.green@139.com
(二)haoJson
类库介绍
haoJson是一款用于json序列化和反序列化处理的C++开源代码库。
支持Windows、Linux的64位平台,使用visual c++或g++进行编译。
遵循标准
JSON格式
json的基本类型有object, array, strings, numbers, booleans, and nulls(json中关键字)。
在一个object中所有的key都要是字符串。
JSON对象
一个JSON对象,无非是括在大括号内的用逗号分隔的键值(名称/值)对。
{“name1”:value1, “name2”:value2 …}
JSON对象可以任意嵌套,以创建更复杂的对象:
{“user”:
{ “userid”: 1900,
“username”: “jsmith”,
“password”: “secret”,
“groups”: [ “admins”, “users”, “maintainers”]
}
}
已定义的JSON语法(参看RFC 4627)中的介绍:
JSON对象封装在大括号内{ }。空对象可以表示为{ }
数组封装在方括号内[ ]。空数组可以表示为 [ ]
成员由一个键-值对代表
成员中的键名应该使用双引号括起来
每个成员都应该有一个对象结构中唯一的键
值如果是字符串,则表示括在双引号中
布尔值使用小写true或false表示
数字使用双精度浮点格式表示;支持科学记数法形式;数字前不应该有零
"攻击(冲突)"(像单、双引号、大、中括号等)性质的字符必须使用反斜杠进行转义
空值由小写null表示
其它类型,如日期,(JSON)本身不支持,应该由解析器/客户端处理转换为字符串
对象或数组每个成员后面必须跟一个逗号,如果它不是最后一个的话
1
2
3
4
5
6
7
8
9
10
11
12
解析算法
移进归约:
Value :
Object
| Array
| Atom
KV :
key ‘:‘ Value
key :
‘"‘ id ‘"‘
KVList :
KVList ‘,‘ KV
| KV
Object :
‘{‘ KVList ‘}‘
| ‘{‘ ‘}‘
ValueList :
ValueList ‘,‘ Value
| Value
Array :
‘[‘ ValueList ‘]‘
| ‘[‘ ‘]‘
Atom :
Short
| UShort
| Int
| UInt
| Long
| ULong
| LongLong
| ULongLong
| Float
| Double
| LongDouble
| String
| Char
| SChar
| UChar
| Bool
| DateTime
| null
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
类库测试
功能测试
sampleClass.h文件
//测试类:学生
JSON_CLASS_DECLARE_BEGIN(Student);
JSON_CLASS_DECLARE_MEMBER(String, Name);//名字
JSON_CLASS_DECLARE_MEMBER(Int, Age);//年龄
JSON_CLASS_DECLARE_MEMBER(Float, Weight);//体重
JSON_CLASS_DECLARE_MEMBER(Float, Height);//身高
JSON_CLASS_DECLARE_MEMBER_ARRAY(String, OptCourse);//选修课程名称列表
JSON_CLASS_DECLARE_MEMBER_ARRAY(Double, OptScore);//选修课程分数列表
JSON_CLASS_DECLARE_END;
////////////////////////////////////////////////////////////////////////////////////////////////////////////
//测试类:班级信息
JSON_CLASS_DECLARE_BEGIN(ClassGrade);
JSON_CLASS_DECLARE_MEMBER(Short, Class);//级
JSON_CLASS_DECLARE_MEMBER(Short, Grade);//班
JSON_CLASS_DECLARE_MEMBER(String, mathTeacher);//数学老师
JSON_CLASS_DECLARE_MEMBER(String, chineseTeacher);//语文老师
JSON_CLASS_DECLARE_MEMBER(DateTime, createTime);//成立时间
JSON_CLASS_DECLARE_MEMBER_ARRAY(Student, Students);//学生列表
JSON_CLASS_DECLARE_END;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
sampleClass.cpp文件
JSON_CLASS_IMPLEMENT(Student);
JSON_CLASS_IMPLEMENT(ClassGrade);
1
2
void test() {
TimeTickType ttt = TimeTickType_Us;
string json;
{
SCOPE_COST_TIME;
//设置3个学生的信息
Student Lily;
Lily.setValue_Name("Lily");
Lily.handOver_Age(NEW Int(10));
Lily.setValue_Height(130.5);
Lily.setNull_Weight();
Lily.addValue_OptCourse("语文");
Lily.addValue_OptCourse("音乐");
Lily.addValue_OptCourse("数学");
Lily.addValue_OptScore(98);
Lily.addValue_OptScore(61);
Lily.addValue_OptScore(-12);
Student Jim = Lily;
String name = "Jim";
Jim.reference_Name(&name);
Jim.setValue_Weight(45);
LOG4J_INFO("Jim.toString():%s", Jim.toString().c_str());
Student Clark = Jim.toString().c_str();
Clark.setValue_Name("clark");
LOG4J_INFO("Clark.toString():%s", Clark.toString().c_str());
//使用点符"Object.member"
String* pName = Clark.Name;
Int* pAge = Clark.Age;
Float* pWeight = Clark.Weight;
Float* pHeight = Clark.Height;
vector<String*>* pOptCourse = Clark.getPointer_OptCourse();
vector<Double*>* pOptScore = Clark.getPointer_OptScore();
vector<Student> listStu;
listStu.push_back(Lily);
listStu.push_back(Jim);
listStu.push_back(Clark);
//设置班级
ClassGrade cg;
cg.setValue_Class(1);
cg.handOver_Grade(NEW Short(2));
cg.addValue_Students(listStu);
cg.setValue_chineseTeacher("Liuming");
cg.handOver_mathTeacher(NEW String("WuXi"));
json = cg.toString();
LOG4J_INFO("toString:%s", json.c_str());
}
LOG4J_INFO("");
{
SCOPE_COST_TIME;
ClassGrade cg;
cg = json.c_str();
json = cg.toString();
LOG4J_INFO("toObject:%s", json.c_str());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
日期时间戳的处理:
jsonFormatter fi;
fi.setInputUserFormat("yyyy年MM月dd日");
fi.setOutputUserFormat("yyyy年MM月dd日");
ClassGrade cg;
cg.setFormatter(DateTime::classID, fi);
cg = "{\"createTime\":\"2020年04月19日\", \"Class\":1,\"Grade\":2,\"mathTeacher\":\"WuXi\",\"chineseTeacher\":\"Liuming\",\"Students\":[{\"Name\":\"Lily\",\"Age\":10,\"Weight\":null,\"Height\":130.500000,\"OptCourse\":[\"语文\",\"音乐\",\"数学\"],\"OptScore\":[98.000000,61.000000,87.000000]},{\"Name\":\"Jim\",\"Age\":10,\"Weight\":45.000000,\"Height\":130.500000,\"OptCourse\":[\"语文\",\"音乐\",\"数学\"],\"OptScore\":[98.000000,61.000000,87.000000]},{\"Name\":\"clark\",\"Age\":10,\"Weight\":45.000000,\"Height\":130.500000,\"OptCourse\":null,\"OptScore\":null}]}";
string cgstr = cg.toString();
1
2
3
4
5
6
7
8
9
性能测试
运行环境
Windows机器信息:
还有以此作为宿主机的vmware虚拟机:
CentOS release 6.10 (Final)
Linux version 2.6.32-754.el6.x86_64
Intel(R) Core(TM) i5-5300U CPU @ 2.30GHz
MemTotal: 1905164 kB
1
2
3
4
软件准备
准备长度为4K的JSON字符串:
{"orderId":10001122589156,"userId":20000298345625,"apId":"223344","apName":"18812340008","feeid":10001122589160,"productVo":{"flowInfo":{"flowId":"direct.archive"},"info":{"serviceId":9990022,"serviceName":"xyz电信+联通体验版(安卓)","serviceCode":"product.4.2-7.2-4.3-7.3.free.android","serviceDesc":"生命周期内一共用1000次,激活后有效期90天","priceId":9990026,"price":0,"priceDesc":"生命周期内一共用1000次,激活后有效期90天","capacityProviderId":58884,"capacityProviderName":"移动认证","instanceId":20000300965248},"baseAttrList":[{"serviceAttrId":20013001,"attrCode":"Name","attrName":"商品名称","attrDesc":"文本,格式:不限","attrType":"text","sortOrder":10,"value":"xyz电信+联通体验版(安卓)","valueName":"xyz电信+联通体验版(安卓)"},{"serviceAttrId":20013002,"attrCode":"Code","attrName":"商品代码","attrDesc":"文本,格式:不限","attrType":"text","sortOrder":20,"value":"product.4.2-7.2-4.3-7.3.free.android","valueName":"product.4.2-7.2-4.3-7.3.free.android"},{"serviceAttrId":20013106,"attrCode":"IntroductionFile","attrName":"介绍材料附件","attrDesc":"文件附件","attrType":"attachment","sortOrder":50,"value":"6AC1C513F7181D36E053284E990A88D1","valueName":"xyz服务能力(xyz)操作指引V1.0.0.docx","attachName":"xyz服务能力(xyz)操作指引V1.0.0.docx"},{"serviceAttrId":20013104,"attrCode":"OrderDesc","attrName":"订购说明","attrDesc":"文本,格式:不限","attrType":"text","sortOrder":70,"value":"订单提交->订单完成","valueName":"订单提交->订单完成"},{"serviceAttrId":20013105,"attrCode":"OrderMax","attrName":"最大订购数量","attrDesc":"整数,格式:整数","attrType":"text","sortOrder":80,"value":"1","valueName":"1"},{"serviceAttrId":20013120,"attrCode":"PublishServiceId","attrName":"发布业务编号","value":"9990022","valueName":"9990022"}],"APAttrList":[{"serviceAttrId":9990023142,"attrId":10016,"attrCode":"activateExperienceText","attrName":"待激活体验版文案","dataSrc":"Text","value":"xyz电信+联通体验版(安卓)还未使用,请尽快根据接入指引完成能力的接入"},{"serviceAttrId":9990023134,"attrId":10016,"attrCode":"canUseExtra","attrName":"可使用套外","dataSrc":"Text","value":"N"},{"serviceAttrId":9990023135,"attrId":10016,"attrCode":"deductMCoin","attrName":"是否走M币扣费","dataSrc":"Text","value":"N"},{"serviceAttrId":9990023136,"attrId":10008,"attrCode":"endCycle","attrName":"周期长度","dataSrc":"SQL","value":"1"},{"serviceAttrId":9990023137,"attrId":10055,"attrCode":"endMode","attrName":"周期类型","dataSrc":"Text","value":"follow"},{"serviceAttrId":9990023138,"attrId":10006,"attrCode":"endTime","attrName":"失效时间","dataSrc":"SQL","value":"2020-06-02 00:00:00"},{"serviceAttrId":9990023143,"attrId":10016,"attrCode":"experienceText","attrName":"使用中体验版文案","dataSrc":"Text","value":"从{#startTime}至{#endTime}期间{#productName}可免费体验{#formount}条,目前剩余{#remain}条。用完即止,过期作废"},{"serviceAttrId":9990023173,"attrId":10016,"attrCode":"exproCapList","attrName":"组合能力信息表","dataSrc":"Text","value":"Y"},{"serviceAttrId":9990023141,"attrId":10016,"attrCode":"hideCostsRule","attrName":"订购次数和计费规则表","dataSrc":"Text","value":"Y"},{"serviceAttrId":9990023166,"attrId":10016,"attrCode":"isShowCapGroup","attrName":"页面是否显示能力组信息","dataSrc":"Text","value":"Y"},{"serviceAttrId":9990023167,"attrId":10016,"attrCode":"isUpdateCapGroup","attrName":"页面能否修改能力组信息","dataSrc":"Text","value":"N"},{"serviceAttrId":9990023139,"attrId":10016,"attrCode":"orderTakePlace","attrName":"是否代下单","dataSrc":"Text","value":"N"},{"serviceAttrId":9990023140,"attrId":10006,"attrCode":"startTime","attrName":"生效时间","dataSrc":"SQL","value":"2020-03-04 00:00:00"}],"appList":[{"appInstanceId":20000300964960,"productInstanceId":9990022,"appId":"300015993685","userId":20000298345625}],"forms":[{"formId":999002316,"serviceClass":"CapGroup","formName":"xyz电信+联通体验版(安卓)","serviceId":999008,"serviceCode":"4.2-7.2-4.3-7.3freeAndroidCapGroup","serviceName":"xyz电信+联通体验版(安卓)","formSelectType":"choice","formAmount":1000,"ruleId":100,"serviceGroupList":[{"serviceId":999008,"itemServiceId":5888024002,"itemServiceCode":"4.2","itemServiceName":"xyz联通版","itemPrice":"5","itemPriceDesc":"0.05元/次"},{"serviceId":999008,"itemServiceId":5888024003,"itemServiceCode":"4.3","itemServiceName":"xyz电信版","itemPrice":"5","itemPriceDesc":"0.05元/次"},{"serviceId":999008,"itemServiceId":5888025002,"itemServiceCode":"7.2","itemServiceName":"本机号码校验联通版","itemPrice":"5","itemPriceDesc":"0.05元/次"},{"serviceId":999008,"itemServiceId":5888025003,"itemServiceCode":"7.3","itemServiceName":"本机号码校验电信版","itemPrice":"5","itemPriceDesc":"0.05元/次"}]}]}}
1
定义以下数据结构:
JSON_CLASS_DECLARE_BEGIN(Flow);
JSON_CLASS_DECLARE_MEMBER(String, flowId);//
JSON_CLASS_DECLARE_END;
JSON_CLASS_DECLARE_BEGIN(Service);
JSON_CLASS_DECLARE_MEMBER(LongLong, serviceId);//
JSON_CLASS_DECLARE_MEMBER(String, serviceName);//
JSON_CLASS_DECLARE_MEMBER(String, serviceCode);//
JSON_CLASS_DECLARE_MEMBER(String, serviceDesc);//
JSON_CLASS_DECLARE_MEMBER(LongLong, priceId);//
JSON_CLASS_DECLARE_MEMBER(Float, price);//
JSON_CLASS_DECLARE_MEMBER(String, priceDesc);//
JSON_CLASS_DECLARE_MEMBER(LongLong, capacityProviderId);//
JSON_CLASS_DECLARE_MEMBER(String, capacityProviderName);//
JSON_CLASS_DECLARE_MEMBER(LongLong, instanceId);//
JSON_CLASS_DECLARE_END;
JSON_CLASS_DECLARE_BEGIN(Attr);
JSON_CLASS_DECLARE_MEMBER(LongLong, serviceAttrId);//
JSON_CLASS_DECLARE_MEMBER(String, attrCode);//
JSON_CLASS_DECLARE_MEMBER(String, attrName);//
JSON_CLASS_DECLARE_MEMBER(String, attrDesc);//
JSON_CLASS_DECLARE_MEMBER(String, attrType);//
JSON_CLASS_DECLARE_MEMBER(Short, sortOrder);//
JSON_CLASS_DECLARE_MEMBER(String, value);//
JSON_CLASS_DECLARE_MEMBER(String, valueName);//
JSON_CLASS_DECLARE_END;
JSON_CLASS_DECLARE_BEGIN(App);
JSON_CLASS_DECLARE_MEMBER(LongLong, appInstanceId);//
JSON_CLASS_DECLARE_MEMBER(LongLong, productInstanceId);//
JSON_CLASS_DECLARE_MEMBER(LongLong, appId);//
JSON_CLASS_DECLARE_MEMBER(LongLong, userId);//
JSON_CLASS_DECLARE_END;
JSON_CLASS_DECLARE_BEGIN(ServiceGroup);
JSON_CLASS_DECLARE_MEMBER(LongLong, serviceId);//
JSON_CLASS_DECLARE_MEMBER(LongLong, itemServiceId);//
JSON_CLASS_DECLARE_MEMBER(String, itemServiceName);//
JSON_CLASS_DECLARE_MEMBER(Float, itemPrice);//
JSON_CLASS_DECLARE_MEMBER(String, itemPriceDesc);//
JSON_CLASS_DECLARE_END;
JSON_CLASS_DECLARE_BEGIN(Form);
JSON_CLASS_DECLARE_MEMBER(LongLong, formId);//
JSON_CLASS_DECLARE_MEMBER(String, formName);//
JSON_CLASS_DECLARE_MEMBER(String, serviceClass);//
JSON_CLASS_DECLARE_MEMBER(LongLong, serviceId);//
JSON_CLASS_DECLARE_MEMBER(String, serviceName);//
JSON_CLASS_DECLARE_MEMBER(String, serviceCode);//
JSON_CLASS_DECLARE_MEMBER(String, serviceDesc);//
JSON_CLASS_DECLARE_MEMBER(String, formSelectType);//
JSON_CLASS_DECLARE_MEMBER(LongLong, formAmount);//
JSON_CLASS_DECLARE_MEMBER(LongLong, ruleId);//
JSON_CLASS_DECLARE_MEMBER_ARRAY(ServiceGroup, serviceGroupList);//
JSON_CLASS_DECLARE_END;
JSON_CLASS_DECLARE_BEGIN(Product);
JSON_CLASS_DECLARE_MEMBER(Flow, flowInfo);//
JSON_CLASS_DECLARE_MEMBER(Service, info);//
JSON_CLASS_DECLARE_MEMBER_ARRAY(Attr, baseAttrList);//
JSON_CLASS_DECLARE_MEMBER_ARRAY(Attr, APAttrList);//
JSON_CLASS_DECLARE_MEMBER_ARRAY(App, appList);//
JSON_CLASS_DECLARE_MEMBER_ARRAY(Form, forms);//
JSON_CLASS_DECLARE_END;
JSON_CLASS_DECLARE_BEGIN(Order);
JSON_CLASS_DECLARE_MEMBER(LongLong, orderId);//
JSON_CLASS_DECLARE_MEMBER(LongLong, userId);//
JSON_CLASS_DECLARE_MEMBER(String, apId);//
JSON_CLASS_DECLARE_MEMBER(String, apName);//
JSON_CLASS_DECLARE_MEMBER(LongLong, feeid);//
JSON_CLASS_DECLARE_MEMBER(Product, productVo);//
JSON_CLASS_DECLARE_END;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
void testOrder() {
TimeTickType ttt = TimeTickType_Us;
string json = "{\"orderId\":10001122589156,\"userId\":20000298345625,\"apId\":\"223344\",\"apName\":\"18812340008\",\"feeid\":10001122589160,\"productVo\":{\"flowInfo\":{\"flowId\":\"direct.archive\"},\"info\":{\"serviceId\":9990022,\"serviceName\":\"xyz电信+联通体验版(安卓)\",\"serviceCode\":\"product.4.2-7.2-4.3-7.3.free.android\",\"serviceDesc\":\"生命周期内一共用1000次,激活后有效期90天\",\"priceId\":9990026,\"price\":0,\"priceDesc\":\"生命周期内一共用1000次,激活后有效期90天\",\"capacityProviderId\":58884,\"capacityProviderName\":\"移动认证\",\"instanceId\":20000300965248},\"baseAttrList\":[{\"serviceAttrId\":20013001,\"attrCode\":\"Name\",\"attrName\":\"商品名称\",\"attrDesc\":\"文本,格式:不限\",\"attrType\":\"text\",\"sortOrder\":10,\"value\":\"xyz电信+联通体验版(安卓)\",\"valueName\":\"xyz电信+联通体验版(安卓)\"},{\"serviceAttrId\":20013002,\"attrCode\":\"Code\",\"attrName\":\"商品代码\",\"attrDesc\":\"文本,格式:不限\",\"attrType\":\"text\",\"sortOrder\":20,\"value\":\"product.4.2-7.2-4.3-7.3.free.android\",\"valueName\":\"product.4.2-7.2-4.3-7.3.free.android\"},{\"serviceAttrId\":20013106,\"attrCode\":\"IntroductionFile\",\"attrName\":\"介绍材料附件\",\"attrDesc\":\"文件附件\",\"attrType\":\"attachment\",\"sortOrder\":50,\"value\":\"6AC1C513F7181D36E053284E990A88D1\",\"valueName\":\"xyz服务能力(xyz)操作指引V1.0.0.docx\",\"attachName\":\"xyz服务能力(xyz)操作指引V1.0.0.docx\"},{\"serviceAttrId\":20013104,\"attrCode\":\"OrderDesc\",\"attrName\":\"订购说明\",\"attrDesc\":\"文本,格式:不限\",\"attrType\":\"text\",\"sortOrder\":70,\"value\":\"订单提交->订单完成\",\"valueName\":\"订单提交->订单完成\"},{\"serviceAttrId\":20013105,\"attrCode\":\"OrderMax\",\"attrName\":\"最大订购数量\",\"attrDesc\":\"整数,格式:整数\",\"attrType\":\"text\",\"sortOrder\":80,\"value\":\"1\",\"valueName\":\"1\"},{\"serviceAttrId\":20013120,\"attrCode\":\"PublishServiceId\",\"attrName\":\"发布业务编号\",\"value\":\"9990022\",\"valueName\":\"9990022\"}],\"APAttrList\":[{\"serviceAttrId\":9990023142,\"attrId\":10016,\"attrCode\":\"activateExperienceText\",\"attrName\":\"待激活体验版文案\",\"dataSrc\":\"Text\",\"value\":\"xyz电信+联通体验版(安卓)还未使用,请尽快根据接入指引完成能力的接入\"},{\"serviceAttrId\":9990023134,\"attrId\":10016,\"attrCode\":\"canUseExtra\",\"attrName\":\"可使用套外\",\"dataSrc\":\"Text\",\"value\":\"N\"},{\"serviceAttrId\":9990023135,\"attrId\":10016,\"attrCode\":\"deductMCoin\",\"attrName\":\"是否走M币扣费\",\"dataSrc\":\"Text\",\"value\":\"N\"},{\"serviceAttrId\":9990023136,\"attrId\":10008,\"attrCode\":\"endCycle\",\"attrName\":\"周期长度\",\"dataSrc\":\"SQL\",\"value\":\"1\"},{\"serviceAttrId\":9990023137,\"attrId\":10055,\"attrCode\":\"endMode\",\"attrName\":\"周期类型\",\"dataSrc\":\"Text\",\"value\":\"follow\"},{\"serviceAttrId\":9990023138,\"attrId\":10006,\"attrCode\":\"endTime\",\"attrName\":\"失效时间\",\"dataSrc\":\"SQL\",\"value\":\"2020-06-02 00:00:00\"},{\"serviceAttrId\":9990023143,\"attrId\":10016,\"attrCode\":\"experienceText\",\"attrName\":\"使用中体验版文案\",\"dataSrc\":\"Text\",\"value\":\"从{#startTime}至{#endTime}期间{#productName}可免费体验{#formount}条,目前剩余{#remain}条。用完即止,过期作废\"},{\"serviceAttrId\":9990023173,\"attrId\":10016,\"attrCode\":\"exproCapList\",\"attrName\":\"组合能力信息表\",\"dataSrc\":\"Text\",\"value\":\"Y\"},{\"serviceAttrId\":9990023141,\"attrId\":10016,\"attrCode\":\"hideCostsRule\",\"attrName\":\"订购次数和计费规则表\",\"dataSrc\":\"Text\",\"value\":\"Y\"},{\"serviceAttrId\":9990023166,\"attrId\":10016,\"attrCode\":\"isShowCapGroup\",\"attrName\":\"页面是否显示能力组信息\",\"dataSrc\":\"Text\",\"value\":\"Y\"},{\"serviceAttrId\":9990023167,\"attrId\":10016,\"attrCode\":\"isUpdateCapGroup\",\"attrName\":\"页面能否修改能力组信息\",\"dataSrc\":\"Text\",\"value\":\"N\"},{\"serviceAttrId\":9990023139,\"attrId\":10016,\"attrCode\":\"orderTakePlace\",\"attrName\":\"是否代下单\",\"dataSrc\":\"Text\",\"value\":\"N\"},{\"serviceAttrId\":9990023140,\"attrId\":10006,\"attrCode\":\"startTime\",\"attrName\":\"生效时间\",\"dataSrc\":\"SQL\",\"value\":\"2020-03-04 00:00:00\"}],\"appList\":[{\"appInstanceId\":20000300964960,\"productInstanceId\":9990022,\"appId\":\"300015993685\",\"userId\":20000298345625}],\"forms\":[{\"formId\":999002316,\"serviceClass\":\"CapGroup\",\"formName\":\"xyz电信+联通体验版(安卓)\",\"serviceId\":999008,\"serviceCode\":\"4.2-7.2-4.3-7.3freeAndroidCapGroup\",\"serviceName\":\"xyz电信+联通体验版(安卓)\",\"formSelectType\":\"choice\",\"formAmount\":1000,\"ruleId\":100,\"serviceGroupList\":[{\"serviceId\":999008,\"itemServiceId\":5888024002,\"itemServiceCode\":\"4.2\",\"itemServiceName\":\"xyz联通版\",\"itemPrice\":\"5\",\"itemPriceDesc\":\"0.05元/次\"},{\"serviceId\":999008,\"itemServiceId\":5888024003,\"itemServiceCode\":\"4.3\",\"itemServiceName\":\"xyz电信版\",\"itemPrice\":\"5\",\"itemPriceDesc\":\"0.05元/次\"},{\"serviceId\":999008,\"itemServiceId\":5888025002,\"itemServiceCode\":\"7.2\",\"itemServiceName\":\"本机号码校验联通版\",\"itemPrice\":\"5\",\"itemPriceDesc\":\"0.05元/次\"},{\"serviceId\":999008,\"itemServiceId\":5888025003,\"itemServiceCode\":\"7.3\",\"itemServiceName\":\"本机号码校验电信版\",\"itemPrice\":\"5\",\"itemPriceDesc\":\"0.05元/次\"}]}]}}";
{
SCOPE_COST_TIME;
Order order = json.c_str();
//性能分析
int n = 100;
ullong startTime = getTimeTick(ttt);
LOG4J_INFO("startTime:%lld", startTime);
for (int i = 0; i < n; ++i) {
json = order.toString();
}
LOG4J_INFO("JSON对象拼装字符串toString耗时: %f us", (double)(getTimeTick(ttt) - startTime) / n);
LOG4J_INFO("toString:%s", json.c_str());
}
LOG4J_INFO("");
{
SCOPE_COST_TIME;
Order order;
//性能分析
int n = 100;
ullong startTime = getTimeTick(ttt);
LOG4J_INFO("startTime:%lld", startTime);
for (int i = 0; i < n; ++i) {
//LOG4J_INFO("i:%d", i);
order = json.c_str();
}
LOG4J_INFO("字符串转JSON对象toObject耗时: %f us", (double)(getTimeTick(ttt) - startTime) / n);
json = order.toString();
LOG4J_INFO("toObject:%s", json.c_str());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
测试结果
JSON对象转JSON字符串toString、JSON字符串转JSON对象toObject,各执行100次取平均耗时。
Windows环境
08:26:49.469 INFO-46820.48372-sampleClass.cpp-140-testOrder JSON对象拼装字符串toString耗时: 12790.000000 us
08:26:57.295 INFO-46820.48372-sampleClass.cpp-159-testOrder 字符串转JSON对象toObject耗时: 77560.000000 us
1
2
Linux环境
17:35:21.485 INFO-20266.-1139853472-sampleClass.cpp-140-testOrder JSON对象拼装字符串toString耗时: 585.760000 us
17:35:21.967 INFO-20266.-1139853472-sampleClass.cpp-159-testOrder 字符串转JSON对象toObject耗时: 4816.390000 us
1
2
(三)haoFrame
采用类似于SpringBoot的框架,快速定制实现restful接口。支持tcp或http协议,使用json格式报文。
//这是haoQueue全部业务的入口
class haoQueueController {
public:
//创建队列
CONTROLLER_FUNCTION_DECLARE("/haoqueue/createqueue", createQueue, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
//查询队列
CONTROLLER_FUNCTION_DECLARE("/haoqueue/queryqueue", queryQueue, NONE, NONE, QueueDefineVo, NONE);
//删除队列
CONTROLLER_FUNCTION_DECLARE("/haoqueue/dropqueue", dropQueue, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
//创建事务
CONTROLLER_FUNCTION_DECLARE("/haoqueue/createtransaction", createTransaction, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
//查询事务
CONTROLLER_FUNCTION_DECLARE("/haoqueue/querytransaction", queryTrans, haoQueueRequestVo, NONE, TransDefineVo, NONE);
//删除事务
CONTROLLER_FUNCTION_DECLARE("/haoqueue/droptransaction", dropTransaction, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
//推送消息-- 一种是无事务推送,需要不传事务ID;一种是事务性推送,需要传入事务ID,并后续需要提交或者回滚。
CONTROLLER_FUNCTION_DECLARE("/haoqueue/push", push, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
//拉取消息-- 必须是事务性拉取,需要不传事务ID,并后续需要提交或者回滚。
CONTROLLER_FUNCTION_DECLARE("/haoqueue/pull", pull, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
//提交事务,需要不传事务ID
CONTROLLER_FUNCTION_DECLARE("/haoqueue/commit", commit, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
//回滚事务,需要不传事务ID
CONTROLLER_FUNCTION_DECLARE("/haoqueue/rollback", rollback, haoQueueRequestVo, NONE, haoQueueResponseVo, NONE);
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(四)haoQueue
幻灯片1
haoQ
ueue架构设计
2020/02/27
幻灯片2
haoQueue原语
?create queue x; //创建队列x
?create queue y; //创建队列y
?create transaction t with x push, y pull; //创建x推送、y拉取的事务t
?push “123” into x; //非事务性推送,数据直接归档
?push “abc” into x with t; //事务性t推送
?pull 1 with t; //事务性t拉取1个消息
?commit t; //提交事务t,将事务内的数据全部归档
?rollback t; //回滚事务,清理事务内的临时数据
?drop transaction t; //删除事务t
?drop queue x; //删除队列x
1
2
3
4
5
6
7
8
9
10
幻灯片3
(一)总体介绍
?这是一个队列事务中间件。首先要定义队列、事务,作为元数据。
?每个队列由数据N个“数据块chunk”组成,每个数据块由M个“数据文件data”组成。chunk作为data的行索引。如果当前chunk的长度已超过限制时,就生成新的块,chunk号总是往上递增的。如果当前chunk的当前data的长度已经超过限制时,就生成新的data,chunk号总是往上递增的。
?队列的处理分为非事务性和事务性两种。其中,向队列中推送消息,可以是非事务性推送,也可以是事务性推送。当使用非事务性推送时,消息将被直接归档chunk和data。
?事务由多个“队列+操作”组成。“操作”有推送、拉取两种类型。事务会将消息缓存到临时chunk和临时data中,当事务提交时,再将数据归档到正式chunk和data。当事务回滚时,临时chunk和临时data会被清理。
幻灯片4
服务端程序框架
?采用C++自研框架haoServerFrame,配置文件config.json。
?支持tcp和http两种协议,其中报文体必须是标准JSON格式,且请求是Request<T1,T2>,响应是Response<T1,T2>的类型。
?可以设定最大连接数server.connect.max,默认20。
?如果连接保持参数server.connect.retain.seconds为0,那么客户端的连接将是短连接;否则当>0,那么在此时间内如无新消息(或心跳),它将被自动断开。
?支持配置IP黑白名单server.ip.white、server.ip.black。
?支持配置数据目录server.path.*,日志目录server.path.log
?
幻灯片5
客户端程序框架
?采用C++自研框架haoClientFrame,配置文件config.json。
?当启动时,客户端会到服务端获取配置,根据服务端某些配置来调整客户端的参数,如client.onnectpool.heartbeat。如果服务端是短连接,那么发心跳是没有意义的。
?可设定心跳时间client.connectpool.heartbeat,当0时不发心跳,对应服务器端是短连接server.connect.retain.seconds=0;当>0时,它应<server.connect.retain.seconds,此处我们取client.connectpool.heartbeat=server.connect.retain.seconds/2。
?支持tcp协议,其中报文体必须是标准JSON格式,且请求是Request<T1,T2>,响应是Response<T1,T2>的类型。
?连接池可以设定最大连接数client.connectpool.max,并发连接服务端的最大数量;最小连接数client.connectpool.min,连接池维持最小的常用连接数。
?可设定日志目录client.path.log
幻灯片6
haoQueueServer的数据目录 datas
meta存放元数据
queue存放队列定义
transaction存放事务定义
chunk存放队列的索引块
data存放队列的数据
幻灯片7
haoQueueServer的数据目录 datas
幻灯片8
haoQueueClient的日志目录 logs
日志分为服务端和客户端日志,每天启动1个文件。
如果当天重复启动多次,那么旧文件将被备份、重命名为.N.bak
幻灯片9
(二)数据结构
?本章节说明meta、queue、transaction、chunk、data五种数据结构。介绍数据结构,解释底层实现机制。
幻灯片10
meta 元数据管理器
?class haoQueueMeta : public scopeLocker
? //队列管理映射
? map<string, haoQueueQueue *> queSet;
? //事务管理映射
? map<string, haoQueueTransaction *> tranSet;
?这个类负责管理队列、事务,进行新增、删除、获取操作。其中“获取”队列主要是为了非事务性推送消息;而“获取”事务则是为了事务性推送、拉取消息。
?当访问haoQueueMeta时,会使用临界区锁,保护queSet和tranSet的线程安全;临界区锁在业务控制函数中使用,详见文件haoQueueController.cpp。
?获取操作会将队列、事务的引用计数加1,而在使用完成后通过代理类refCountDecrProxy将引用计数减1(或显式调用decrRefCount),以确保删除操作要在其他操作完成之后进行。
?删除队列,需要判断有没有事务定义有关联操作此队列。如有则报错,请删除事务后,再删除队列;如没有则可以删除。
幻灯片11
元数据文件
?文件名称:meta
?由于队列、事务可增可删,文件长度的变化可长可短,在覆盖写入文件时,需要考虑新内容比旧内容长度短的情况。通过在文件开头储存一个int整数,来表示文件中元数据的有效长度。
?文件内容变更时,调用fwrite一次性写入的,不存在部分写成功部分写失败的情况。
幻灯片12
队列定义
?class haoQueueQueue : public autoPointer 注:此处的int无用。
?这个类负责管理队列定义信息,它包含了名称queueCode[32]、开始块号startChunk、下一待分配块号nextChunk(从0开始),以及将队列定义写入文件和从文件加载的功能。
?applyPushChunk:在向队列推送消息时,可查询当前可用块号,如当前块已满,则分配新的块号并生成新的块。
?push:非事务性推送消息,直接归档到队列。
?pull:当事务性拉取时,由事务对象调用。从指定的块chunkId和块内偏移offset开始读取最多pullCnt个消息。如果块内消息个数不足,则继续读取下一个块,直到读够pullCount个或读完最后一个块为止。
?applyBlankSegment:当事务预提交时,由事务对象调用,用于在块内生成指定长度的空白空间,之后再覆写。
幻灯片13
队列定义文件
?文件名称:x.queue
?存储有效块号区间,内容为开始块号和下一待分配块号,所以是固定长度2个USLLONG,共16个byte。
?文件内容变更时,调用fwrite一次性写入的,不存在部分写成功部分写失败的情况。
幻灯片14
块chunk
?class haoQueueChunk
?这个类负责管理队列的一个块,成员变量有块号、指向上属队列定义的指针、指向下属data的指针,具有读写块文件的功能。
?
?isFull:判断本块是否容量满了。
?push:非事务性推送消息,直接归档到队列。由队列对象调用。
?pull:当事务性拉取时,由事务对象调用。从指定的块内偏移offset开始读取最多n个消息。要么读够n个消息,要么读完本块为止。
?applyBlankSegment:当事务预提交时,由事务对象调用,用于在块内生成指定长度的空白空间。
?coverBlankSegment:当事务提交时,由事务对象调用,用于推送消息的归档,它会覆写预提交时所生成的空白空间。
幻灯片15
块文件结构
?文件名称:x.n.chunk,相当于队列数据的索引文件
?每个块单元为结构体struct chunkFileDataUnit,单元长度为32bytes:
?
?
?
?
?
?
?
?
?no为数据所在chunk下属数据文件的序号;
?offset为数据在数据文件中的偏移;
?length为数据在数据文件中的长度;
?time为数据的创建时间
?我们约定当time>0 && length>0时,块索引单元是已提交的;当time>0&& length==0时,块索引单元是预提交的;当time=0时,此单元是手工修改为跳过的,拉取时会忽略。多个预提交单元组成一个空白段,空白段位于正式chunk文件中。在提交归档之前,空白段与临时chunk文件中的数据没有直接关系。
幻灯片16
数据data
?class haoQueueData
?这个类负责管理队列的一个块下属全部的数据文件,成员变量有数据文件序号集合set dataNo、指向上属块的指针pChunk,具有读写数据文件的功能。
?write:向指定序号的数据文件,写入指定偏移量、指定长度的数据。当序号文件不存在或当前最大序号的文件已满时,将新创建一个新数据文件,序号往上递增。
?read:从指定序号的数据文件中,读取指定偏移量、指定长度的数据。
?构造函数入参为指向上属块的指针。序号从0开始,循环判断数据目录中的数据文件是否存在,如存在将序号插入到数据文件序号集合。
幻灯片17
数据文件
?文件名称:x.n.m.data,存储队列的实际数据。
?
?
?
?
幻灯片18
事务transaction
?class haoQueueTransaction
?这个类负责管理事务,成员变量有事务char transId[32]、队列的操作组合map<string, queueTransOperate *> queueOperate。在新定义事务时,须指定各队列的操作类型推送或拉取;不允许修改事务的队列操作,但可以删除事务定义。
?在队列的操作组合中,string是队列的名称,而queueTransOperate *指向整个事务数据结构中所对应的操作对象的位置。
?push:通过此事务向队列推送n条消息。首先判断事务中是否有此队列的操作,不允许非定义范围的操作;如果事务还没有启动则启动之;计算n条消息的总长度,并将全部消息转存到一个char数组;如果临时文件不存在,那么生成临时chunk文件和临时data文件;往临时文件中追加索引数据和数据内容。
?pull:事务级拉取消息,在每次拉取时,逐次遍历各个索引块,并记录访问的块内偏移。
幻灯片19
事务数据结构transactionFileFormat
?文件名称:t.trans,存储事务数据。
?
?
?
?
各个队列可推送和拉取,拉取操作结果保存在pullRecord
推送操作结果保存在pushCache中。
当整个事务数据结构内容变更时,调用fwrite一次性写
入的,不存在部分写成功部分写失败的情况。
最后,我们计算一下事务数据结构占用空间:
当事务t中有n个队列操作时,size = 24 + (40+56+32)n=24+128n
幻灯片20
事务拉取数据结构queuePullRecord
?
?
?
?
拉取操作只需要记录最后所在的块号、偏移。A和B用于记录拉取历史,分为以下几种情况:
(1)事务被定义后,队列从未拉取过Count=0,A无效、B无效。1将向2转化。
(2)事务被定义后,之前队列从未拉取过,但本次事务开始并且未提交/回滚时Count=1,A有效、B无效;A里有最近拉取块号和偏移,并且A的isCommited=N。2将向3转化,即A.isCommited从N变为Y。
(3)当之前队列有拉取并提交过,那么事务提交/回滚后Count=1,A有效、B无效;A里有最近拉取块号和偏移,且A的isCommited=Y。3将向4转化。
(4)当之前队列有拉取并提交过,那么本次事务开始但未提交/回滚时Count=2,A.isCommited=Y;B有效并且有最近拉取块号和偏移,B.isCommited=N。4将向3转化:当commit时,将未提交B覆盖了到A;当rollback时,A保持不动。
拉取操作在一个事务中可以进行多次。可以看出,A用于记录首次“待提交”,之后一直用于记录“最后提交”;而B一直用于记录非首次的“待提交”。
幻灯片21
事务推送数据结构tmpPushChunkCache
?
?
?
?
当向事务t、队列x推送n个消息时,在临时数据文件t.x.pushdat.tmp中写入全部消息。同时,将在临时块文件t.x.pushchk.tmp中生成n个索引,每个索引先记录下各消息在临时数据文件t.x.pushdat.tmp中的偏移offset和length。在事务提交阶段,在归档时将两个临时文件分别整体追加到正式文件末尾,并且重算各索引的offset。
最后在tmpPushChunkCache中,使用msgCount累计消息总数,使用msgLength累计消息的总长度。由于覆盖写入的问题,这两个数据用于标记临时文件的有效长度。
推送操作在一个事务中可以进行多次。
幻灯片22
(三)事务处理
前面我们提到事务中关于队列的推送、拉取数据组织,下面说明事务提交的过程处理。
事务管理(ACID)
谈到事务一般都是以下四点
原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
一致性(Consistency)
事务前后数据的完整性必须保持一致。
隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性(Durability)
持久性是指一个事务一旦被提交,它对库中数据的改变就是永久性的,接下来即使库发生故障也不应该对其有任何影响。
?
?
?
?
幻灯片23
事务状态
定义事务四种状态:
?
?
?
?
事务开始:当事务为TransactionStatus_Start、TransactionStatus_Commit、TransactionStatus_Rollback时,才可以开始。
见haoQueueTransaction::beginTrans,此时要重置事务transactionFileFormat数据结构。
事务预提交:当事务为TransactionStatus_Start时,才可以预提交。
见haoQueueTransaction::doPreCommit()。
事务提交:当事务为TransactionStatus_Precommit时,才可以提交。
见haoQueueTransaction::Commit()。
事务回滚:当事务为TransactionStatus_Start时,才可以回滚。
见haoQueueTransaction::Rollback()。
幻灯片24
事务提交的两个阶段之一“预提交”
haoQueueTransaction::doPreCommit
当事务t提交Commit时,t所处状态必须是“事务已开始”,如果t没有任何队列的推送或拉取操作记录,则事务是未开始的,没有可提交的事务。“预提交”是为了最后做“提交”准备,事先准备好需要的空间,避免各个队列操作在逐个归档时出现部分成功部分失败的情况,保证事务的原子性。
事务数据transactionFileFormat在内存中备份为t2。对事务中各个队列的queueTransOperate操作进行处理:
(1)预提交只处理队列的推送操作,这是因为推送涉及临时索引和
临时数据文件。如果推送消息msgCount个数为0则跳过此队列的预处理。
(2)从队列当前可用块的尾部,申请一个空白段,容量为msgCount个索引。之所以叫空白,即在没有真正覆写正式索引之前,即时访问到这些索引,这些索引也是无效的,要被忽略。haoQueueQueue::applyBlankSegment(USINT msgCount, USLLONG & chunkId, USLLONG & chunkOffset, USLLONG & chunkLength)
入参为msgCount,出参是tmpPushChunkCache中的chunkId、chunkOffset、chunkLength。
(3)如果队列申请空白段失败,那么要将事务t恢复到t2备份的内容,返回失败。
当全部队列的推送操作处理完毕后,将事务t的状态改为“预提交TransactionStatus_Precommit”状态,并且将transactionFileFormat更新保存到事务文件。
?
?
?
?
幻灯片25
推送临时块和临时数据的预提交
下一个队列
对事务transactionFileFormat t
t.status=TransactionStatus_Start
t.status=TransactionStatus_Precommit
x.tmpPushChunkCache
记录下空白段所在的
chunkId块号
chunkOffset偏移
chunkLength长度
t.save()
完成
在x.n.chunk块申请
msgCount个空白索引
空白段中的索引单元全部是空白索引,见前面<块文件结构>的描述:
我们约定当time>0 && length>0时,块索引单元是已提交的;而time>0 && length==0这是一个预提交的空白索引。
幻灯片26
事务提交的两个阶段之二“提交”
haoQueueTransaction::doCommit
当事务t提交Commit时,系统会先做doPreCommit,再做doCommit。因此,在doCommit时,t的状态已经是TransactionStatus_Precommit。事务数据transactionFileFormat在内存中备份为t2。对事务中各个队列的操作queueTransOperate op进行处理:
(1)当定义有队列拉取操作,调用doCommitPull(op)。
(2)当定义有队列推送操作,调用doCommitPush(op)。
(3)如果前面处理出现失败,那么要将事务t恢复到t2备份的内容,
返回失败。
当全部队列的推送操作处理完毕后,将事务t的状态改为
“提交TransactionStatus_Commit”状态,并且将transactionFileFormat
更新保存到事务文件。
至此,haoQueue实现了一致性和持久性。因为的事务本身在定
义时,就已经同其他事务分开,而事务中队列的操作过程的记录,
也是按事务进行存储,自然具有隔离性的。
?
?
?
?
幻灯片27
提交之doCommitPush
x.n.chunk
x.n.m.data
t.status=TransactionStatus_Precommit
预提交时申请的空白段
位置o
第2步,根据预提交时x.tmpPushChunkCache写x.n.chunk,offset += o
第1步,写x.n.m.data
如果在doCommit中间的任何一个点程序挂死,当haoQueue系统在重启时(入口见haoQueueMeta::initialize),会检查是否有预提交的事务。如有,那么根据x.tmpPushChunkCache重做redo上述过程。由于第1步和第2步是两个写动作,因此在redo时,可能会造成x.n.m.data之前写入的空间被丢弃,但不影响系统的正确性。
幻灯片28
提交之doCommitPull
事务中队列操作x.quePullRec中的数据结构,见前面<事务拉取数据结构>的说明。
当Count=1时,说明队列操作是首次拉取,A记录了首次“待提交”的块号chunkId和块内索引offset,并且A.isCommited应为N;将A.isCommited改为Y,处理完毕。
当Count=2时,说明队列操作非首次拉取,A记录了“最后提交”的块号chunkId和块内索引offset,并且A.isCommited应为Y;而B记录了非首次的“待提交”的块号chunkId和块内偏移offset,并且B.isCommited应为N。
将B.chunkId和B.offset覆盖到A.chunkId和A.offset,将Count改为1,最后重置B,处理完毕。
幻灯片29
事务回滚
只有在开始状态的事务,才能被回滚。
回滚操作,只是将transactionFileFormat.status改为
TransactionStatus_Rollback,然后覆写事务文件t.x.trans。
幻灯片30
并发控制
涉及并发控制的有meta、queue、transaction三种对象。
meta是全局单例,它包含了queue集合、transaction集合的映射,为确保线程安全,meta的访问是串行的。在得到queue/transaction指针之前,会将指向对象的引用计数加一;使用用完毕后,再将引用计数减一。删除动作,则会等待引用计数归零。
大部分并发控制在haoQueueController通过对queue、transaction加锁实现。而需要在更深的代码中进行加锁的,包括以下逻辑处理:
(1)事务在预提交推送操作时,需要在队列的chunk块中申请空白段时
(2)事务在提交推送操作时,需要在队列的data文件中追加“临时data”时
幻灯片31
事务push对pull的限制
队列中的每个消息应该被t1拉取消费并只消费1次。但由于t2预提交和提交存在时间差,也没有锁住队列x,
t1有可能已经跳过了空白段,这样导致部分消息被消费0次的情况。
针对这个问题,t1在遇到第1个空白索引时,则终止拉取,这时其他事务继续完成提交。这样又会产生
一个新问题,事务t2的提交如果一直不完成,比如说t2提交的处理线程异常挂掉了,其他事务的拉取都被
终止,此时要怎么办?这就需要有一个异常检测及处理的机制。
幻灯片32
事务提交的异常处理
?当事务在没有完成预提交前,突然进程挂掉,那么事务还处于开始状态,可以在系统重启后再重新发起提交;
?当事务完成了预提交后,突然进程挂掉,那么在重启时,系统会自动完成提交;
?当事务在没有完成预提交前,突然线程挂掉,那么事务还处于开始状态,可以在系统重启后再重新发起提交;
?当事务完成了预提交后,突然线程挂掉,这也是上一节提到的异常情况,会导致其他所有事务的拉取不可继续。系统有以下两个处理机制:
?(1)记录首次检测拉取到空白索引的时间,如果时间超过1分钟,则认为是这种异常,那么系统要遍历全部的待提交事务,匹配上块号、偏移、长度等信息,找到事务则由系统自动提交之。
?(2)重启系统。如果重启还是解决不了,那么只能摒弃此事务,运维人员可以使用工具,往空白段中各个索引写入跳过标识。拉取操作见到此标识,则跳过继续往下。
?
(五)haoQueue操作手册
幻灯片1
haoQueue操作手册
2020/04/30
幻灯片2
编译手册
?代码说明
? 只支持64位编译
?
?编译环境
?Windows : Microsoft Visual Studio Community 2019/Microsoft Visual C++ 2019
? 预处理加上WIN64
?
?CentOS : g++,Makefile已写好,直接make
?
?运行说明
?Windows : haoQueue config_windows.json
?CentOS : haoQueueServer config_linux.json
1
2
幻灯片3
haoQueueWeb部署
?代码说明
?haoQueue的前端应用样
?例,基于angularjs编写。
?可以在tomcat里部署,
?你也可以选择自己的
?容器。 本例是在本地
?Windows机器phpStudy
?下面进行部署,如图:
?
幻灯片4
前端启动
幻灯片5
后台启动
?本例是使用CentOS环境运行
?
?下面是成功启动的日志
幻灯片6
前端页面
?打开chrome浏览器,看看队列和事务:
?
幻灯片7
新建队列、消息推送push(非事务式)
?从左侧”队列管理“进入,点击右上角“新建队列”按钮,填写队列名称“123”,并点击右边”保存“按钮;队列建立后,点击”推送“,注意这里推送的数据是直接进入队列的。如图:
?
幻灯片8
新建事务、消息推送和拉取
?从左侧”事务管理“进入,点击右上角“新建事务”按钮,填写事务名称“abc”,并点击右边”保存“按钮,如图:
?
幻灯片9
事务式消息推送push
幻灯片10
事务式消息拉取pull
幻灯片11
事务说明
对同一事务内的n个推送操作+m个拉取操作进行提交或者回滚。
下面是提交事务成功的页面提示:
原文:https://www.cnblogs.com/haoLIbs/p/12819154.html