@Override
public
void
run() {
try
{
int
logCount
= 0;
// we do this in an attempt to ensure that not all of the servers
// in the ensemble take a snapshot at the same time
int
randRoll
=
r
.nextInt(
snapCount
/2);
while
(
true
) {
Request
si
=
null
;
//要输出数据为空则等待
if
(
toFlush
.isEmpty()) {
//processRequest(Request request) 时queuedRequests.add(request);
//单机版这儿为PrepRequestProcessor发送过来的request
si
=
queuedRequests
.take();
}
else
{
//poll()算法为非阻塞算法,立即返回或等待一会再返回
si
=
queuedRequests
.poll();
//当期没有请求进来时
if
(
si
==
null
) {
//提交所有遗留的request的日志,执行next.processRequest
flush(
toFlush
);
continue
;
}
}
if
(
si
==
requestOfDeath
) {
break
;
}
if
(
si
!=
null
) {
// track the number of records written to the log
//记录写入日志记录写入日志的记录数,如果成功记录
//据说这步是区分是事物还是非事物,非事物返回false
if
(
zks
.getZKDatabase().append(
si
)) {
logCount
++;
//logCount>snapCount/2+(0-snapCount/2)
//这么做是为了所有服务器不再同一时间采用快照
if
(
logCount
> (
snapCount
/ 2 +
randRoll
)) {
randRoll
=
r
.nextInt(
snapCount
/2);
// roll the log
zks
.getZKDatabase().rollLog();
// take a snapshot
if
(
snapInProcess
!=
null
&&
snapInProcess
.isAlive()) {
LOG
.warn(
"Too busy to snap, skipping"
);
}
else
{
//保存数据
snapInProcess
=
new
ZooKeeperThread(
"Snapshot Thread"
) {
public
void
run() {
try
{
zks
.takeSnapshot();
}
catch
(Exception
e
) {
LOG
.warn(
"Unexpected exception"
,
e
);
}
}
};
snapInProcess
.start();
}
logCount
= 0;
}
}
else
if
(
toFlush
.isEmpty()) {
//之前没有遗留请求,则执行下一个请求加工处理器
// optimization for read heavy workloads
// iff this is a read, and there are no pending
// flushes (writes), then just pass this to the next
// processor
if
(
nextProcessor
!=
null
) {
nextProcessor
.processRequest(
si
);
if
(
nextProcessor
instanceof
Flushable) {
((Flushable)
nextProcessor
).flush();
}
}
continue
;
}
toFlush
.add(
si
);
//遗留请求超过1000时,对遗留请求进行处理,还有一个处理是,再上面开头
//上面开头。当前没有请求进来时,对遗留请求进行处理
if
(
toFlush
.size() > 1000) {
//提交所有遗留的request日志,执行next.processRequest
flush(
toFlush
);
}
}
}
}
catch
(Throwable
t
) {
handleException(
this
.getName(),
t
);
}
finally
{
running
=
false
;
}
LOG
.info(
"SyncRequestProcessor exited!"
);
}
主要操作:
1.自旋操作
2.判断未写入日志请求
toFlush
是否为空 ,若为空,则阻塞等待新的请求,若不为空,则非阻塞获取请求,若无请求可获取,则写入日志
3.收到死亡请求跳出自旋
4.如果是事物请求,zkdatabase添加日志,并判断日志数量
logCount是否达到snapCount(发生几次snapCount,就会执行一次快照)/2+0到snapCount/2 次数,若达到,生成数据快照
为什么会有个区间,是为了避免,所有服务器同一时间写入日志
5.如果非事物,若
toFlush为空,则执行下一个请求加工处理器。
6.若都不是,则把request添加至
toFlush,等待写入日志