UniqueId类方法getOrCreateId()源码解析

版权声明:如若转载,请联系作者。 https://blog.csdn.net/liu16659/article/details/82957186

UniqueId类方法getOrCreateId()源码解析

1.UniqueId类

2.getOrCreateId()

  • 先看方法注释:
/*
Finds the ID associated with a given name or creates it.
寻找或者是创建与给出的名字相应的ID

This method is blocking. Its use within OpenTSDB itself is discouraged, please usegetOrCreateIdAsync instead.
这个方法是blocking(阻塞的)。它的使用在openTSDB中是不被鼓励的,相反请使用getOrCreateIdAsync

The length of the byte array is fixed in advance by the implementation.
数组的长度是固定的,由实现提前确定

@param name The name to lookup in the table or to assign an ID to.
 在表中寻找到的,亦或是即将分配ID的name
 
@throws HBaseException if there is a problem communicating with HBase.
 如果和HBase 通信有问题,则会抛出HBaseException

@throws IllegalStateException if all possible IDs are already assigned.
 如果所有可能的IDs均匀被分配,则抛出IllegalStateException

@throws IllegalStateException if the ID found in HBase is encoded on the  wrong number of bytes.
 如果在HBase中发现的ID是用错误的字节数编码,则抛出IllegalStatExcepetion
*/
  • 再看方法具体代码
  public byte[] getOrCreateId(final String name) throws HBaseException {
    try {
        //异步调用,这里是先寻找name所对应的id是否存在,如果不存在的话,就需要分配一个id
      return getIdAsync(name).joinUninterruptibly();
    } catch (NoSuchUniqueName e) {
      if (tsdb != null && tsdb.getUidFilter() != null && tsdb.getUidFilter().fillterUIDAssignments()) {//如果被阻塞了,就不需要再分配id
        try {
          if (!tsdb.getUidFilter().allowUIDAssignment(type, name, null, null).join()) {
            rejected_assignments++;//
            throw new FailedToAssignUniqueIdException(new String(kind), name, 0, "Blocked by UID filter.");
          }
        } catch (FailedToAssignUniqueIdException e1) {
          throw e1;
        } catch (InterruptedException e1) {
          LOG.error("Interrupted", e1);
          Thread.currentThread().interrupt();
        } catch (Exception e1) {
          throw new RuntimeException("Should never be here", e1);
        }
      }
      
	//接着开启正确的分配UID之路
      Deferred<byte[]> assignment = null;  //首先new一个Deferred对象
      boolean pending = false; //将pending置为false【pending:adj,即将发生的;悬而未决的】
      synchronized (pending_assignments) {
        assignment = pending_assignments.get(name);
        if (assignment == null) {
          // to prevent UID leaks that can be caused when multiple time
          // series for the same metric or tags arrive, we need to write a 
          // deferred to the pending map as quickly as possible. Then we can 
          // start the assignment process after we've stashed the deferred 
          // and released the lock
          assignment = new Deferred<byte[]>();
          pending_assignments.put(name, assignment);
        } else {
          pending = true;
        }
      }
      
      if (pending) {
        LOG.info("Already waiting for UID assignment: " + name);
        try {
          return assignment.joinUninterruptibly();
        } catch (Exception e1) {
          throw new RuntimeException("Should never be here", e1);
        }
      }
      
      // start the assignment dance after stashing the deferred
      byte[] uid = null;
      try {
        uid = new UniqueIdAllocator(name, assignment).tryAllocate().joinUninterruptibly();
      } catch (RuntimeException e1) {
        throw e1;
      } catch (Exception e1) {
        throw new RuntimeException("Should never be here", e);
      } finally {
        synchronized (pending_assignments) {
          if (pending_assignments.remove(name) != null) {
            LOG.info("Completed pending assignment for: " + name);
          }
        }
      }
      return uid;
    } catch (Exception e) {
      throw new RuntimeException("Should never be here", e);
    }
  }

针对上述的getOrCreateId()代码,依照顺序往下查看,在try..catch块中包含一个getIdAsync(finla String name)方法。getIdAsync(name)这个方法返回一个Deferred<byte[]>类型对象。getIdAsync()方法代码如下:

  public Deferred<byte[]> getIdAsync(final String name) {
    //从内存中检索name对应的id --> the result is byte[]
      final byte[] id = getIdFromCache(name); //getIdFromCache()其实是一个方法,内部调用name_cache[ConcurrentHashMap类型]
    if (id != null) {
      cache_hits++;//cache访问数增加
      return Deferred.fromResult(id);//返回一个Deferred对象
    }
    cache_misses++;//否则cache_misses增加 -->表示没有在cache中查询到

      //类GetIdCB实现Callback,那么GetIdCB就是一个Callback了
    class GetIdCB implements Callback<byte[], byte[]> {//实现Callback()接口
        //下面这个call()方法是 覆写Callback接口中的
        public byte[] call(final byte[] id) {
        if (id == null) {
          throw new NoSuchUniqueName(kind(), name);
        }

        //如果二者长度不等【说明id的长度不符合规范】 --> 抛出异常【注意这里的抛出异常语句可以单独存在,而不是非要跟在方法后面】
        if (id.length != id_width) {
          throw new IllegalStateException("Found id.length = " + id.length
                                          + " which is != " + id_width
                                          + " required for '" + kind() + '\'');
        }
        addIdToCache(name, id);
        addNameToCache(id, name);
        return id;
      }
      public String toString(){
          return "this function is added by LittleLawson";
      }
    }
    //getIdFromHBase(name)这个应该会发出一个RPC,所以将这个请求结果添加了一个回调函数
    Deferred<byte[]> d = getIdFromHBase(name).addCallback(new GetIdCB());
    return d;
  }

在调用getIdAsync(name)之后,又调用了一个joinUninterruptibly()方法。现在查看该方法:

  • 首先看该方法的注释
 /**
   Synchronously waits until this Deferred is called back.
同步等待,直到这个Deferred对象被回调。

This helps do synchronous operations using an asynchronous API. If this Deferred already completed, this method returns (or throws)  immediately.
这帮助我们使用一个异步的API做一个同步的操作。如果这个Deferred对象已经完成了,这个放回将会立即返回或者抛出。

Otherwise, the current thread will be blocked  and will wait until the Deferred is called back.  If the current thread  gets interrupted while waiting, it will keep waiting anyway until the   callback chain terminates, before returning (or throwing an exception)  the interrupted status on the thread will be set again.
否则,当前的线程将会被阻塞并且将会等待直到Deferred被调用返回,如果Deferred对象在等待的过程中,当前线程被中断,它将会保持等待直到callback链中断,在返回(或者抛出异常)之前,线程中断的状态将会被重新设置。

   @return The deferred result, at this point in the callback chain.
返回值:此刻callback链deferred对象的结果

   @throws Exception if the deferred result is an exception, this exception  will be thrown.
   抛出异常:如果deferred结果是一个异常,这个异常将会被抛出
   */
  • 再看该方法具体的代码
 public T joinUninterruptibly() throws Exception {
   try {
     return doJoin(false, 0);
   } catch (InterruptedException e) {
     throw new AssertionError("Impossible");
   }
 }
  • fromResult()方法
  /**
Constructs a Deferred with a result that's readily available.
构建一个Deferred,它的result是方便读取的。

This is equivalent to writing:
这与下面的写法是等价的:
Deferred<T> d = new Deferred<T>();
d.callback(result);

Callbacks added to this Deferred will be immediately called.
加入到这个Deferred对象的callbacks将会被立即调用。

@param result The "deferred" result. // 延迟的结果
@return a new Deferred. //返回一个新的Deferred对象
*/
  public static <T> Deferred<T> fromResult(final T result) {
    return new Deferred<T>(result);
  }

查看Callback接口

  • 先看接口定义
 A simple 1-argument callback interface.
简单到只有一个参数的接口—callback

 Callbacks are typically created as anonymous classes.  In order to make  debugging easier, it is recommended to override the toString method so that it returns a string that briefly explains what the callback does.
 If you use  Deferred  with DEBUG logging turned on, this will be really useful to understand what's in the callback chains.
Callbacks经常被用于创建一个匿名的类。为了让调试更加简单,推荐覆盖从Object中继承而来的toString()方法,所以它返回一个字符串,这个字符串简单明了的解释了这个callback做什么。
如果你在DEBUG logging开启时使用Deferred,这将非常有利于去理解在callback链中到底发生了什么。

 @param <R> The return type of the callback. 
	callback返回的类型-->泛型
	
 @param <T> The argument type of the callback.
	callback的参数类型-->泛型
	
 @throws Exception any exception.
   抛出任何异常
  • 再看Callback的代码
/*1.传递了两个泛型作为入参*/   
public interface Callback<R, T> {
  public R call(T arg) throws Exception;

  /** The identity function (returns its argument).  */
  //标志函数(返回它的参数)
  public static final Callback<Object, Object> PASSTHROUGH =
    new Callback<Object, Object>() {
      public Object call(final Object arg) {
        return arg;
      }
      public String toString() {
        return "passthrough";
      }
    };
}

在callback中调用call方法时,会使用到下面这个类,构造一个对象,调用语句如下:
throw new NoSuchUnqiueName(kind(),name)【为什么这里需要抛出异常?不符合常理】

NoSuchUniqueName.java

package net.opentsdb.uid;
import java.util.NoSuchElementException;
/**
 * Exception used when a name's Unique ID can't be found.
 * 当一个name的唯一ID不能被找到时抛出异常。
 * @see UniqueId
 */
public final class NoSuchUniqueName extends NoSuchElementException {

  /** The 'kind' of the table.  */
  //表类型
  private final String kind;
  
  /** The name that couldn't be found.  */
  //name不能被找到
  private final String name;

  /**
   * Constructor.
   *
   * @param kind The kind of unique ID that triggered the exception.
		引发异常发生的唯一ID的类型,
   * @param name The name that couldn't be found.
		不能被找到的name
   */
  public NoSuchUniqueName(final String kind, final String name) {
    super("No such name for '" + kind + "': '" + name + "'");
    this.kind = kind;
    this.name = name;
  }

  /** Returns the kind of unique ID that couldn't be found.  */
  public String kind() {
    return kind;
  }

  /** Returns the name for which the unique ID couldn't be found.  */
  public String name() {
    return name;
  }

  static final long serialVersionUID = 1266815261;
}

这里使用的NoSuchUniqueName(final String kind, final String name)这个构造方法,但是这个kind是一个String类型的字符串,但是为何UniquId中却是new NoSuchUniqueName(kind(), name)这条语句呢?这里面的kind()是个方法。具体了解一下:

  //a function, return a string
  public String kind() {
    return fromBytes(kind);
  }

再看一下fromBytes()方法。

  //从字节数组返回一个String
  private static String fromBytes(final byte[] b) {
    return new String(b, CHARSET);//根据指定的CHARSET构建一个String
  }

接着看一些CHARSET,

  /** Charset used to convert Strings to byte arrays and back. */
  //用于将字符串<->字节数组的编码字符集 =》这里使用的是ISO-8859-1
  private static final Charset CHARSET = Charset.forName("ISO-8859-1");

接着往下走,就是比较id的长度是否符合规范,如果不符合规范,则抛出异常,否则将其添加到缓存中。

private void addIdToCache(final String name, final byte[] id) {
    byte[] found = name_cache.get(name);
    if (found == null) {//如果暂无对应的映射
      found = name_cache.putIfAbsent(name,
                                    // Must make a defensive copy to be immune to any changes the caller may do on the array later on.
									//如果
                                    Arrays.copyOf(id, id.length));
    }
    if (found != null && !Arrays.equals(found, id)) {//如果已有name->id的映射
      throw new IllegalStateException("name=" + name + " => id="
          + Arrays.toString(id) + ", already mapped to "
          + Arrays.toString(found));
    }
  }

介绍一下name_cache

	/** Cache for forward mappings (name to ID). */
	//预缓冲name到ID的映射
	//Creates a new, empty map with the default initial table size (16). ->创建一个新的,空的map,使用默认的初始表大小(16)
	//ConcurrentHashMap:A hash table supporting full concurrency of retrievals and high expected concurrency for updates.
	//一个哈希表:支持检索完全的并行,并且为更新的高期待的并发
  private final ConcurrentHashMap<String, byte[]> name_cache =
    new ConcurrentHashMap<String, byte[]>();

name_cache是一个ConcurrentHashMap类型的map映射。如果这个name_cache中不包含name所在的映射,name使用putIfAbset()方法,将name和其对应的id放进去。
如果根据name找到了相应的id,但他们并非同一个id, 就抛出一个异常。【异常信息是,name所对应的id已经在使用了,请不要再次映射】
因为tsuid表中存储的是双向映射,所以还有一个方法进行id->name映射的缓存。

  private void addNameToCache(final byte[] id, final String name) {
    final String key = fromBytes(id);
    String found = id_cache.get(key);
    if (found == null) {
      found = id_cache.putIfAbsent(key, name);
    }
    if (found != null && !found.equals(name)) {
      throw new IllegalStateException("id=" + Arrays.toString(id) + " => name="
          + name + ", already mapped to " + found);
    }
  }

addNameToCache(final byte[] id,final String name)方法就是id->name的映射。大致原理同addIdToCache(…)方法

/**
1.Returns the cell of the specified row key, using family:kind.
返回指定行键的具体单元值,使用的列族是kind【想想为什么是kind?】

2.hbaseGet()方法返回的是一个Deferred<byte[]>对象,因为是异步过程
3.
/
private Deferred<byte[]> hbaseGet(final byte[] key, final byte[] family) {
/
*
1.GetRequest:Reads something from HBase
2.table是从HBase中需要寻找的table;key是上述table中的key
**/
final GetRequest get = new GetRequest(table, key);

get.family(family).qualifier(kind);
class GetCB implements Callback<byte[], ArrayList<KeyValue>> {
  public byte[] call(final ArrayList<KeyValue> row) {
    if (row == null || row.isEmpty()) {
      return null;
    }
    return row.get(0).value();
  }
}
/*给一个Deferred对象添加callback()函数
执行流程如下:
1.client是一个异步的HBaseClient实例
2.get()方法是从GetRequest实例对象中检索数据【Retrieves data from HBase】
3.client.get(get)这个方法将会得到一个Deferred对象 --> 称其为Deferred 对象A
4.在Deferred对象A上再添加一个回调函数,其中的参数是GetCB的一个实例对象。这个addcallback(new GetCB())返回的是一个Deferred对象
*/
return client.get(get).addCallback(new GetCB());

}

/**

  • Specifies a particular column family to get.
  • @param family The column family.
  • This byte array will NOT be copied.
  • @return {@code this}, always.
    */
    public GetRequest family(final byte[] family) {
    KeyValue.checkFamily(family); //首先需要在KeyValue中检查是否真的有这个family,
    this.family = family;//然后将这个family放到get对象中 的family 【byte[]】中
    return this;
    }

同理,qulifier()与family()道理相似,也是将这个列族注册到get对象中。
/**

  • Specifies a particular column qualifier to get.
  • @param qualifier The column qualifier.
  • This byte array will NOT be copied.
  • @return {@code this}, always.
    */
    public GetRequest qualifier(final byte[] qualifier) {
    if (qualifier == null) {
    throw new NullPointerException(“qualifier”);
    }
    KeyValue.checkQualifier(qualifier);
    this.qualifiers = new byte[][] { qualifier };
    return this;
    }
    在类中又定义了一个GetCB类【其实就是GetCallBack】实现了 Callback这个接口,传递的参数类型是byte[]和ArrayList。
    接着判断这个结果返回是不是空;否则就返回值。
    然后就是发送rpc请求,直接开启一个子线程去等待远端调用结果。
    这个GetCB()类实现了Callback()接口

接下来看client.get(get)中的get()方法。【注:这个方法返回一个Deferred对象。】
/**

  • Retrieves data from HBase.
  • @param request The {@code get} request.
  • @return A deferred list of key-values that matched the get request.
    */
    public Deferred<ArrayList> get(final GetRequest request) {
    num_gets.increment();
    return sendRpcToRegion(request).addCallbacks(got, Callback.PASSTHROUGH);
    }
    这里的num_gets的定义如下:
 // Number of calls to {@link #get}.   
  private final Counter num_gets = new Counter();  

接着看sendRpcToRegion()这个方法

/**
    Sends an RPC targeted at a particular region to the right RegionServer.
	发送一个指向特定region的RPC,到正确的regionserver
    
    This method is package-private so that the low-level {@link RegionClient}
    can retry RPCs when handling a {@link NotServingRegionException}.
    这个方法是package-private,所以low-level RegionClient能够重试RPCs,在处理一个NotServingRegionException时。
	
	@param request The RPC to send.  This RPC must specify a single specific table and row key.
    @return The deferred result of the RPC (whatever object or exception was de-serialized back from the network).
   */
  Deferred<Object> sendRpcToRegion(final HBaseRpc request) {//无public 修饰
    if (cannotRetryRequest(request)) {//检验RPC过程是否可以再次重试?
      return tooManyAttempts(request, null);//否则报次数太多错
    }
    request.attempt++;//每有一次尝试,都会计数
    final byte[] table = request.table;//得到请求的表
    final byte[] key = request.key;//得到请求的具体rowkey
	
    //其中RegionInfo:Stores basic information about a region.
	final RegionInfo region = getRegion(table, key);//从table,rowkey信息得出region的信息
	
	/*
	1.内部类  实现Callback接口。传递的参数是Deferred<Object>,Object
	2.只是定义一个内部类,不一定真正调用
	*/
    final class RetryRpc implements Callback<Deferred<Object>, Object> {
      public Deferred<Object> call(final Object arg) {
        if (arg instanceof NonRecoverableException) {
          // No point in retrying here, so fail the RPC.  ->在这里重试没有意义,所以直接失败
          HBaseException e = (NonRecoverableException) arg;
          if (e instanceof HasFailedRpcException
              && ((HasFailedRpcException) e).getFailedRpc() != request) {
            // If we get here it's because a dependent RPC (such as a META
            // lookup) has failed.  Therefore the exception we're getting
            // indicates that the META lookup failed, but we need to return
            // to our caller here that it's their RPC that failed.  Here we
            // re-create the exception but with the correct RPC in argument.
            e = e.make(e, request);  // e is likely a PleaseThrottleException.
          }
          request.callback(e);
          return Deferred.fromError(e);//调用errorback()
        }
        return sendRpcToRegion(request);  // Retry the RPC.  --> why need retry?
      }
      public String toString() {
        return "retry RPC";
      }
    }

    if (region != null) {//如果region真正存在
      if (knownToBeNSREd(region)) {//见下代码分析  ->  region不可用
        final NotServingRegionException nsre =
          new NotServingRegionException("Region known to be unavailable",
                                        request);
        final Deferred<Object> d = request.getDeferred();
        handleNSRE(request, region.name(), nsre);
        return d;
      }
	  
	  //新建一个RegionClient,根据之前的region信息得到
      final RegionClient client = clientFor(region);
      if (client != null && client.isAlive()) {//如果region有效
        request.setRegion(region);
        final Deferred<Object> d = request.getDeferred();//获取deferred对象
        client.sendRpc(request);//再
        return d;
      }
    }
    return locateRegion(request, table, key).addBothDeferring(new RetryRpc());
  }
  /**
    Returns true if this region is known to be NSRE'd and shouldn't be used.    
	如果region能够被NSRE识别,并且不能使用,那么则返回true。
   */
  private static boolean knownToBeNSREd(final RegionInfo region) {
    return region.table() == EMPTY_ARRAY;
  }

再看clientFor()方法,传递的参数是hiRegionInfo

  /**
   Returns the client currently known to hose the given region, or NULL.
   返回目前已经给定的region的client hose,否则为null。
   */
  private RegionClient clientFor(final RegionInfo region) {
    if (region == null) {
      return null;
    } else if (region == META_REGION || Bytes.equals(region.table(), ROOT)) {
      // HBase 0.95+: META_REGION (which is 0.95 specific) is our root.
      // HBase 0.94 and earlier: if we're looking for -ROOT-, stop here.
      return rootregion;
    }
    return region2client.get(region);
  }

其中的rootregion如下:

/**
  The client currently connected to the -ROOT- region.
  连接到-ROOT- region所在的client
  
  If this is null then we currently don't know where the -ROOT- region is and we're waiting for a notification from ZooKeeper to tell us where it is.
  Note that with HBase 0.95, has_root would be false, and this would instead point to the .META. region.
  如果rootregion为null,那么我们目前将不清楚-ROOT- region将会在哪儿,并且我将正在等待一个通知来自zookeeper,去告诉我们-ROOT-是在哪儿。
  注意:在HBase 0.95版本时,has_root()方法将会返回false,所以就会直接指向.META. 所在的region。
  */
 private volatile RegionClient rootregion;
  /** Package private way of accessing / creating the Deferred of this RPC.  */
  package private级:访问或创建这次RPC过程的Deferred对象
  final Deferred<Object> getDeferred() {
    if (deferred == null) {
      deferred = new Deferred<Object>();//new 一个Deferred对象
    }
    return deferred;
  }

分析sendRpc(HBaseRpc rpc)

 /**
   Sends an RPC out to the wire, or queues it if we're disconnected.
   发送一个RPC到网络中,或者如果我们不能连接的时候,将其排队。【什么叫在不能连接的时候,将其排队?】
   
   [important]: Make sure you've got a reference to the Deferred of this RPC ({@link HBaseRpc#getDeferred}) before you call this method.  Otherwise there's a race condition if the RPC completes before you get a chance to call {@link HBaseRpc#getDeferred} (since presumably you'll need to either return that Deferred or attach a callback to it).
   【重要的是】: 在你调用这个方法之前,确保你已经得到一个指向这个RPC(HBaseRpc getDeferred)的Deferred对象的引用。 否则,将有一个race condition,如果RPC完成在你得到机会调用HBaseRpc getDeferred。(因为可以假定你将需要要么返回Deferred或者添加一个callback)
   */
  void sendRpc(HBaseRpc rpc) {
    if (chan != null) {
      if (rpc instanceof BatchableRpc
          && (server_version >= SERVER_VERSION_092_OR_ABOVE  // Before 0.92,
              || rpc instanceof PutRequest)) {  // we could only batch "put".
        final BatchableRpc edit = (BatchableRpc) rpc;
        if (edit.canBuffer() && hbase_client.getFlushInterval() > 0) {
          bufferEdit(edit);
          return;
        }
        addSingleEditCallbacks(edit);
      } else if (rpc instanceof MultiAction) {
        // Transform single-edit multi-put into single-put.
        final MultiAction batch = (MultiAction) rpc;
        if (batch.size() == 1) {
          rpc = multiActionToSingleAction(batch);
        } else {
          hbase_client.num_multi_rpcs.increment();
        }
      }
      final ChannelBuffer serialized = encode(rpc);
      if (serialized == null) {  // Error during encoding.
        return;  // Stop here.  RPC has been failed already.
      }
      final Channel chan = this.chan;  // Volatile read.
      if (chan != null) {  // Double check if we disconnected during encode().
        // if our channel isn't able to write, we want to properly queue and
        // retry the RPC later or fail it immediately so we don't fill up the
        // channel's buffer.
        if (check_write_status && !chan.isWritable()) {
          rpc.callback(new PleaseThrottleException("Region client [" + this + 
              " ] channel is not writeable.", null, rpc, rpc.getDeferred()));
          removeRpc(rpc, false);
          writes_blocked.incrementAndGet();
          return;
        }
        
        rpc.enqueueTimeout(this);
        Channels.write(chan, serialized);
        rpcs_sent.incrementAndGet();
        return;
      }  // else: continue to the "we're disconnected" code path below.
    }

    boolean tryagain = false;
    boolean dead;  // Shadows this.dead;
    synchronized (this) {
      dead = this.dead;
      // Check if we got connected while entering this synchronized block.
      if (chan != null) {
        tryagain = true;
      } else if (!dead) {
        if (pending_rpcs == null) {
          pending_rpcs = new ArrayList<HBaseRpc>();
        }
        if (pending_limit > 0 && pending_rpcs.size() >= pending_limit) {
          rpc.callback(new PleaseThrottleException(
              "Exceeded the pending RPC limit", null, rpc, rpc.getDeferred()));
          pending_breached.incrementAndGet();
          return;
        }
        pending_rpcs.add(rpc);
      }
    }
    if (dead) {
      if (rpc.getRegion() == null  // Can't retry, dunno where it should go.
          || rpc.failfast()) {
        rpc.callback(new ConnectionResetException(null));
      } else {
        hbase_client.sendRpcToRegion(rpc);  // Re-schedule the RPC.
      }
      return;
    } else if (tryagain) {
      // This recursion will not lead to a loop because we only get here if we
      // connected while entering the synchronized block above. So when trying
      // a second time,  we will either succeed to send the RPC if we're still
      // connected, or fail through to the code below if we got disconnected
      // in the mean time.
      sendRpc(rpc);
      return;
    }
    LOG.debug("RPC queued: {}", rpc);
  }
 /** 
   @return The UID filter object, may be null. UID 过滤器对象,可能为空。
   @since 2.3 
   */
  public UniqueIdFilterPlugin getUidFilter() {
    return uid_filter;
  }

其中的uid_filter如下:

  /** A filter plugin for allowing or blocking UIDs 
	一个为了允许或者阻塞UIDs的过滤器插件
  */
  private UniqueIdFilterPlugin uid_filter;

其中UniqueIdFilterPlugin的介绍如下:
A filter that can determine whether or not UIDs should be allowed assignment based on their metric and tags.
一个过滤器,能够决定UIDs是否应该被分配基于它们的metric一件tags。

  /**
   Whether or not the filter should process UIDs. [过滤器是否应该处理UIDs]
   @return True if allowUIDAssignment(UniqueIdType, String, String, Map)
   should be called, false if not.
   */
  public abstract boolean fillterUIDAssignments();

分配失败时,

/** How many times assignments have been rejected by the UID filter 
	因为UID filter而导致的分配失败次数
*/
  private volatile int rejected_assignments;
  /** Map of pending UID assignments
   1.即将分配UID的 map 集合  —>需要使用map将Deferred对象保存起来,方便以后找到。
   2.上述这个知识点可以在Deferred类的介绍中详细了解
   */
  private final HashMap<String, Deferred<byte[]>> pending_assignments =
    new HashMap<String, Deferred<byte[]>>();
/**
   Synchronously waits until this Deferred is called back.
   同步的锁等待直到这个Deferred对象被调用返回。
   
   This helps do synchronous operations using an asynchronous API.
   这个帮助做同步操作使用异步的API。
   
   If this Deferred already completed, this method returns (or throws) immediately.  Otherwise, the current thread will be <em>blocked</em> and will wait until the Deferred is called back.  If the current thread gets interrupted while waiting, it will keep waiting anyway until the callback chain terminates, before returning (or throwing an exception) the interrupted status on the thread will be set again.
	如果这个Deferred已经完成了,这个方法将会立即返回(或者抛出)。否则,目前的线程将会被阻塞,并且等到Deferred对象调用返回。如果目前的线程在等待时被中断,在返回(或者抛出异常)之前,那么这个中断的状态将会被再次设置。
   
   @return The deferred result, at this point in the callback chain.
   @throws Exception if the deferred result is an exception, this exception
   will be thrown.
   */
  public T joinUninterruptibly() throws Exception {
    try {
      return doJoin(false, 0);
    } catch (InterruptedException e) {
      throw new AssertionError("Impossible");
    }
  }

如下是一个构造函数,用于分配一个新的UID.
/**
Implements the process to allocate a new UID.
分配一个新的UID的实现进程

This callback is re-used multiple times in a four step process:
1. Allocate a new UID via atomic increment.
2. Create the reverse mapping (ID to name).
3. Create the forward mapping (name to ID).
4. Return the new UID to the caller.
这个回调函数可以重用多次,处理过程为下列的四个步骤:
1.分配一个新的UID通过自增方式
2.创建一个逆向映射(id->name)
3.创建一个正向的映射(name->ID)
4.返回一个新的UID给调用者
*/
UniqueIdAllocator实现了Callback()这个接口。

    UniqueIdAllocator(final String name, final Deferred<byte[]> assignment) {
      this.name = name;
      this.assignment = assignment;
    }

猜你喜欢

转载自blog.csdn.net/liu16659/article/details/82957186