HDFS中的Diff类——用来描述两个集合的不同

HDFS中的Diff类——用来描述两个集合的不同

概述

Diff类,用来描述集合状态的变化,e.g.

  1. 集合中存在元素{e1, e2, e3},假设集合状态为previous
  2. 向集合中添加元素e4,此时集合中元素为{e1, e2, e3, e4},状态为current,那么可以用一个Diff对象刻画previous到current的变化,意味着已知previous,diff,可求current,反之亦然。

我们知道,对于集合操作,无非增删查改,而涉及到集合状态的变化——即集合元素的变化,有增删改三种情况,那么如何通过一个对象来描述这三种情况呢?

对于被删除的元素,单独放在一个list中;对于新添加的元素,单独放在一个list中;对于修改的元素,视为删除旧元素,增加新元素。

其中,将存放新添加元素的list称为create-list,即clist,将存放删除元素的list称为delete-list,即dlist。那么,我们可以将集合中元素的状态以一个二元组的形式表达

(0, 0)	元素既不在clist中,也不在dlist中
(c, 0)	元素在clist中,不在dlist中
(0, d)	元素不在clist中,但是在dlist中
(c, d)	元素既在clist中,也在dlist中

假设集合set1的初始状态为state1,现在创建了一个diff1对象记录集合set1的状态变化。对于任一元素element1,无论初始状态下其是否存在于set1中,它的状态都为(0, 0),即此刻它既不在diff1对象的clist中,也不在diff1对象的dlist中。元素具体的状态跃迁算法如下:

1. 当元素element1不在集合set1的初始状态state1中时:						(0, 0)
	1.1 创建元素element1:将element1加入到diff1对象的clist中			(c, 0)
		1.1.1 创建元素element1,然后再次创建element1					error
		1.1.2 创建元素element1,然后删除element1						(0, 0)
		1.1.3 创建元素element1,然后修改element1						(c', 0)
	1.2 删除元素elemnt1												error
	1.3 修改元素elment1												error
	
2. 当元素element1在集合set1的初始状态state1中时:						(0, 0)
	2.1 创建元素element1												(error)
	2.2 删除元素element1												(0, d)
		2.2.1 删除元素element1,然后创建元素element1					(c, d)
		2.2.2 删除元素element1,然后删除元素element1					error
		2.2.3 删除元素element1,然后修改元素element1					error
	2.3 修改元素element1												(c, d)
		2.3.1 修改元素element1,然后创建元素element1					error
		2.3.2 修改元素element1,然后删除元素element1					(0, d)
		2.3.3 修改元素element1,然后修改元素element1					(c', d)

相关类

1. ListType

枚举类,Diff类用来描述list类型

public enum ListType{
    CREATED, DELETED
}

2. Element

即元素类,Diff类将集合中的元素包装成Element对象

public interface Element<K> extends Comparable<K>{
    K getKey();
}

3. Processor

public class Processor<E> {
    void process(E element);
}

4. Contaner

只包含一个元素的类

public class Container<E> {
    private final E element;
    private Container(E element){
        this.element = element;
    }
    
    public E getElement(){
        return element;
    }
}

5. UndoInfo

类似于rollback,在每次操作的时候,记录修改的信息,若操作失败,可通过UndoInfo对象进行回滚操作

public static class UndoInfo<E> {
    private final int createdInsertionPoint;
    private final E trashed;
    private final Integer deletedInsertionPoint;
    
    private UndoInfo(final int createdInsertionPoint, final E trashed, final Integer deletedInsertionPoint){
        this.createdInsertionPoint = createdInsertionPonit;
        this.trashed = trashed;
        this.deletedInsertionPoint = deletedInsertionPoint;
    }
    
    public E getTrashedElement(){
        return trashed;
    }
}

Diff类

Diff可以说是HDFS快照架构中最核心的一个类,理解了Diff,剩下的东西便迎刃而解

public class Diff<K, E extends Diff.Element<K>> {
    private static final int DEFAULT_ARRAY_INITIAL_CAPACITY = 4;
    private List<E> created;
    private List<E> deleted;
    
    protected Diff(){
        //do nothing
        //就是告诉子类,你们自己玩,初始化的时候不用考虑我,我自己可以的
    }
    
    protected Diff(final List<E> created, List<E> deleted){
        this.created = created;
        this.deleted = deleted;
    }
    
    public List<E> getList(final ListType type){
        final List<E> list = type == ListType.CREATED ? created : deleted;
        return list == null ? Collections.<E>emptyList() : list;
    }
    
    public int searchIndex(final ListType type, final K name){
        return search(getList(type), name);
    }
    
    /**
    关于二分查找,如果存在于list中,那么返回index;否则,返回(-(insertionpoint) - 1)
    **/
    public static <K, E extends Comparable<K>> int search(final List<E> element, final K name){
        return elements == null ? -1 : Collections.binarySearch(elements, name);
    }
    
    public E search(final ListType type, final K name){
        final List<E> list = getList(type);
        final int c = search(list, name);
        return c < 0 ? null : list.get(c);
    }
    
    public boolean isEmpty(){
        return (created == null || created.isEmpty()) &&
            	(deleted == null || deleted.isEmpty());
    }
    
    private void insert(final ListType type, final E element, fina int i){
        List<E> list = type == ListType.CREATED ? created : deleted;
        //首先方法是private,内部方法,大概率是先调用search,发现返回值<0,即不存在所求list中,再调用insert
        //所以index,即i值应该是小于0的
        if(i >= 0){
            throw new AssertionError("Element already exists");
        }
        
        if(list == null){
            list = new ArrayList<E>(DEFAULT_ARRAY_INITIAL_CAPACITY);
            if(type == ListType.CREATED){
                created = list;
            }else if(type == ListType.DELETED){
                deleted = list;
            }
        }
        //(-(insertionpoint) - 1) = i --> insertionpoint = -i - 1
        list.add(-i - 1, element);
    }
    
    /**
    create()操作,rollback操作不需要借助UndoInfo对象
    因为create()只需要将element添加到clist中,用不到dlist的Index
    **/
    public int create(final E element){
        final int c = search(created, element.getKey());
        insert(ListType.CREATED, element, c);
        //这里的c是(-(insertionpoint) - 1)
        return c;
    }
    
    public void undoCreate(final E element, final int insertionPoint){
        remove(created, insertionPoint, element);
    }
    
    private static <E> void remove(final List<E> elements, final int i, final E expected){
        final E removed = elements.remove(-i - 1);
        Preconditions.checkState(expected == removed);
    }
    
    /**
    delete()操作,两种情况
    	1. 被删除的元素element在diff中的状态为(c, x)
    		1.1 当x=0时,证明element是新创建的元素,那么直接在clist中将其剔除即可
    		1.2 当x=d时,证明element是被修改的元素,那么保留在dlist中即可,将其在clist中剔除
    	2. 被删除的元素element在diff中的状态为(y, d)
    		2.1 当y=0时,证明element已经被删除过了,此时为非法操作
    		2.2 当y=c时,为1.2
    **/
    public UndoInfo<E> delete(final E element){
        final int c =search(created, element.getKey());
        E previous = null;
        Integer d = null;
        //对应于(c, 0)或者(c, d),然后删除,只需要将element从clist中移除即可
        if(c >= 0){
            previous.created.remove(c);
        }else {
            d = search(deleted, element.getKey());
            insert(ListType.DELETED, element, d);
        }
        return new UndoInfo<E>(c, previous, d);
    }
    
    public void undoDelete(final E element, final UndoInfo<E> undoInfo){
        final int c = undoInfo.createdInsertionPoint;
        if(c >= 0){
            created.add(c, undoInfo.trashed);
        }else{
            remove(deleted, undoInfo.deletedInsertionPoint, element);
        }
    }
    
    public UndoInfo modify(final E oldElement, final E newElement){
        Preconditions.checkArgument(oldElement != newElement);
        Preconditions.checkArgument(oleElement.compareTo(newElement.getKey()) == 0);
        
        final int c = search(created, newElement.getKey());
        E previous = null;
        Integer d = null;
        //存在于clist中,(c, x) --> (c', x)
        if(c >= 0){
            previous = created.set(c, newElement);
            previous = oldElement;
        }else{ //element既不在clist中,也不再dlist中,但是结合的初始状态下,element已存在
            //(0, 0) --> (c, d)
            d = search(deleted, oldElement.getKey());
            if(d < 0){
                insert(ListType.CREATED, newElement, c);
                insert(ListType.DELETED, oldElement, d);
            }
            //else (0, d),再进行修改为非法操作
        }
        //走else的时候,这里放置的是null,其实这个方法和undoModify()方法还是有些问题的
        return new UndoInfo<E>(c, previous, d);
    }
    
    public void undoModify(final E oldElement, final E newElement, final UndoInfo<E> undoInfo){
        final int c = undoInfo.createdInsertionPoint;//(c', x) -> (c, x)
        if(c >= 0){
            created.set(c, undoInfo.trashed);
        }else {
            final int d = undoInfo.deletedInsertionPoint;
            if(d < 0){
                remove(created, c, newElement);
                remove(deleted, d, oldElement);
            }
        }
    }
    
    /**
    Find an element in the previous state
    集合为set1,diff对象用来描述集合set1从previous到current状态的跃迁,给定一个元素element1,求其在set1为previous时对应的Element对象
    **/
    public Container<E> accessPrevious(final K name){
        return accessPrevious(name, created, deleted);
    }
    
    private static <K, E extends Diff.Element<K>> Container<E> accessPrevious(
    	final K name, final List<E> clist, final List<E> dlist){
        final int d = search(dlist, name);
        //存在于dlist中
        if(d >= 0){
            return new Container<E> dlist.get(d);
        }else {
            final int c = search(clist, name);
            return c < 0 ? null : new Container<E>(null);
        }
    }
    
    //如果element存在于clist中,直接返回该元素即可
    //	否则,如果element不存在与dlist中,说明其当前状态为null,如果存在于dlist中,说明其状态为(Container)null
    public Conatiner<E> accessCurrent(K name){
        return accessPrevious(name, deleted, created);
    }
    
    //集合为set1,diff对象用来描述集合set1从previous到current状态的跃迁,给定previous状态下集合的元素,通过diff对象求得current状态下集合的元素
    public List<E> apply2Previous(final List<E> previous){
    	return apply2Previous(previous, getList(ListType.CREATED), getList(ListType.DELETED));
    }
    
    private static <K, E extends Diff.Element<K>> List<E> apply2Previous(
    							final List<E> previous, final List<E> clist, final List<E> dlist){
        final List<E> tmp = new ArrayList<E>(previous.size() - dlist.size());
        final Iterator<E> i = previous.iterator();
        //将previous中不在dlist中的元素添加到tmp中
        for(E deleted : dlist){
            E e = i.next();
            int cmp = 0;
            for(; (cmp = e.compareTo(deleted.getKey())) < 0; e = i.next()){
                tmp.add(e);
            }
        }
        for(; i.hasNext()){
            tmp.add(i.next());
        }
        //综上,已经将previous中不在dlist中的元素添加到tmp中,但是分析一下,元素elemnt1有如下几种情况会放入dlist中
        	//1. (0, d),就是单纯的被删除了
        	//2. (c, d), 是被修改过的元素,那么这个元素还要在clist中找到新的状态
        
        //对于(c, 0)的元素,只需要单纯的添加一下就可以了
        final List<E> current = new ArrayList<E>(tmp.size() + clist.size());
        final Iterator<E> tmpIterator = tmp.iterator();
        final Iterator<E> cIterator = clist.iterator();
        
        E t = tmpIterator.hasNext() ? tmpIterator.next() : null;
        E c = cIterator.hasNext() ? cIterator.next() : null;
        for(; t != null || c != null){
            //未完待续
        }
    }
    
    public List<E> apply2Current(final List<E> current){
        return apply2Previous(current, getList(ListType.DELETED), getList(ListType.CREATED));
    }
    
    //合并两个diff
    public void combinePosterior(final Diff<K, E> posterior,
      final Processor<E> deletedProcesser) {
        //未完待续
    }
}

针对合并两个diff对象说明如下:

集合set1状态跃迁 previous–> current–> poster

diffPreToCur用来描述previous到current的状态跃迁

diffCurToPoster用来描述current到poster的状态跃迁

1. 在diffCurToPoster对象中,元素element的状态为(0, 0):
	什么都不用做
2. 在diffCurToPoster对象中,元素element的状态为(c, 0)
	2.1 在diffPreToCur对象中:(c', 0)			error
	2.2 在diffPreToCur对象中:(0, d')			(c, d')
	2.3 在diffPreToCur对象中:(c', d')		error
	2.4 在diffPreToCur对象中:(0, 0)			(c, 0)
	
3. 在diffCurToPoster对象中,元素element的状态为(0, d)
	3.1 在diffPreToCur对象中:(c', 0)			(0, 0)
	3.2 在diffPreToCur对象中:(0, d')			error
	3.3 在diffPreToCur对象中:(c', d')		(0, d')
	3.4 在diffPreToCur对象中:(0, 0)			(0, d)
	
4. 在diffCurToPoster对象中,元素element的状态为(c, d)
	4.1 在diffPreToCur对象中:(c', 0)			(c, 0)
	4.2 在diffPreToCur对象中:(0, d')			error
	4.3 在diffPreToCur对象中:(c', d')		(c, d')
	4.4 在diffPreToCur对象中:(0, 0)			(c, d)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值