5、讨论:
1、由Journal的Address和ID组成其URI,NN应该为其生成唯一的JournalID
2、Journal可以被构建,格式化,强制格式化。格式化意味着创建一个新的JournalID,强制格式化意味着删除老的。
3、如果一个stream已经被open了,再来进行getOutputStream()应该抛出异常
4、getInputStream应该返回一个从特定txid开始inputStream
5、purgeTransation判断能否安全的删除到所有到指定txid的Transaction
6、EditLogOutputStream.setVersion()应该保证任何的后续Transaction必须使用这个新的version
7、EditLogInputStream.readNext()应该读向下一个Transaction,后续的getTxnId或者getVersion都应该返回这个Transaction的相关属性。
readNext()会将底层的流指向下一个Transaction的开始位置,所以如果应用调用getTxn()可以直接读取到这个Transaction而避免buffer-copy。出于这个原因,EditLogInputStream也实现InputStream去直接读取底层流
8、EditLogInputStream.mark()表示这个输入流最多可以读到mark调用的前一个Transaction。这方法和Checkpoint中的roll方法类似。
9、getNumberOfTransactions(sinceTxnId)返回Journal中可以提供的从sinceTxnId开始的Transaction数量
10、roll方法可以去掉,因为mark完全可以取代
11、当某一checkpointer通知NN开始进行checkpoint,NN将在outputstream上进行mark。那样,所有到mark为止的Transaction都会被checkpointer读取到。
12、新增sync方法,因为在写入editlog的thread一把都是在对namespace进行write,持有写锁,异步的写入可以使得thread尽早释放写锁。
6、Error secnarios
1、当一个outputStream由于权限,空间不足,网络等问题不能创建时,getOutputStream会抛出异常,然后进行重试或者中止
2、如果EditLogOutputStream.write()调用不能完成时,需要抛出异常。这时NN可以将该stream关闭,然后将该Journal加入到bad Journal列表。后续可以尝试将该Journal进行restore,如果成功,可以在该stream上再次进行getOutputStream()。这个情况下,这个Journal会丢失一些Transactions,因此无法提供老的Transactions。另一方面对于client来说,write的异常使得client要么进行重试写入该Transaction,但是不能跳过这个而写入下一个Transaction。
3、一个打开的Stream必须要保证Transaction是顺序的并连续的。但如果是一个新打开的Stream,到时可以不接着上一个Transaction的txid连续的。但是必须要记录这个流不能提供老的Transactions
4、如果Journal失效一段时间然后在写入的时候,就会出现Transaction空洞。那么这时候调用getInputStream(long sinceTxnId)正好是空洞中的Transaction时,将抛出异常。这就意味这Journal必须记录自己能提供的Transactions
5、另外getNumberOfTransactions(long sinceTxnId)在sinceTxnId之后发现空洞,也会抛出异常
6、readNext如果不能完整的读取一个Transaction,也抛出异常,这是客户端可以:
a、抛弃这个Journal
b、关闭这个inputstream,从下一个Txit打开另一个inputstream
7、如果Client检查到Transaction损坏时,要么抛弃这个Journal,要么关闭这个inputStream,从下一个txit打开下一个inputstream
7、JournalSet
JournalSet和Journal具有一致的接口,如前所述JournalSet将一系列的Journals在内部并行操作,对外部而言,就像只有一个Journal,所以它的接口和Journal是一致的。接口如下:
public class JournalSet implements Journal {
JournalSet(Configuration conf, URI u, boolean format, boolean force) ;
//List of journals
private List<Journal> listOfJournals;
}
JournalSet的构造函数需要从conf中获取Journal的配置,并将其放入到listOfJournals列表中管理。
写入时,JournalSet会将写入流分流的写入到各个Journals内去
读取时,JournalSet会选择一个它认为最好的Journal进行读取
getNumberOfTransactions返回所有流能读到的最大值
purgeTransactions会作用到所有的底层流中