2021SC@SDUSC
上篇,我们分析了NonSpillableDataBag,本篇,我们将分析三种"spillable"DataBag
Data目录下包含bag的文件列表如下:
回忆一下bag的类图
上篇提到,创建bag的方法有两种,一种是调用BagFactory的方法,创建的是三种spillableDataBag,另一种是直接调用nonSpillableDataBag
先去看看三种DataBag,三者继承于DefaultAbstractBag,DefaultAbstractBag实现DataBag接口,上篇已经对接口类进行了分析,总结如下
下面分析DefaultAbstractBag源码
/**
* DataBag的默认实现。这是一个抽象类,用作所有这三种类型的数据包的父类。
*/
@SuppressWarnings("serial")
public abstract class DefaultAbstractBag implements DataBag {
private static final Log log = LogFactory.getLog(DataBag.class);
// If we grow past 100K, may be worthwhile to register.
private static final int SPILL_REGISTER_THRESHOLD = 100 * 1024;
private static PigLogger pigLogger;
private static InterSedes sedes = InterSedesFactory.getInterSedesInstance();
// 保存元组的容器。由子类实例化的实际对象。
protected Collection<Tuple> mContents;
// 我们已经创建了Spill文件。这些需要在最后定型时删除。
protected FileList mSpillFiles;
//总大小,包括磁盘上的元组。存储在这里,这样当人们询问时,我们就不用遍历磁盘了。
protected long mSize = 0;
// 每个包需要抽样的元组数目,以得到元组大小的估计
private static final int SPILL_SAMPLE_SIZE = 100;
private static final int SPILL_SAMPLE_FREQUENCY = 10;
long aggSampleTupleSize = 0;
int sampled = 0;
private boolean spillableRegistered = false;
/**
* 获取包中元素的数量,包括内存和磁盘上的元素。
*/
@Override
public long size() {
return mSize;
}
/**
* 对每个SPILL_SAMPLE_FREQUENCYth元组进行采样,直到达到SPILL_SAMPLE_SIZE的最大值,以获得元组大小的估计
*/
protected void sampleContents() {
synchronized (mContents) {
Iterator<Tuple> iter = mContents.iterator();
for (int i = 0; i < sampled * SPILL_SAMPLE_FREQUENCY && iter.hasNext(); i++) {
iter.next();
}
for (int i = sampled; iter.hasNext() && sampled < SPILL_SAMPLE_SIZE; i++) {
Tuple t = iter.next();
if (t != null && i % SPILL_SAMPLE_FREQUENCY == 0) {
aggSampleTupleSize += t.getMemorySize();
sampled += 1;
}
}
}
}
/**
* 向包中添加一个元组。
* @param t tuple to add.
*/
@Override
public void add(Tuple t) {
synchronized (mContents) {
mSize++;
mContents.add(t);
}
markSpillableIfNecessary();
}
/**
* 所有袋子实现都应该在每次添加元素后调用这个方法。
*/