package io.netty.util;

import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.atomic.AtomicReferenceArray;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
* Default {@link AttributeMap} implementation which use simple synchronization per bucket to keep the memory overhead
* as low as possible.
*/
public class DefaultAttributeMap implements AttributeMap {

//以原子方式更新attributes变量的引用
@SuppressWarnings("rawtypes")
private static final AtomicReferenceFieldUpdater<DefaultAttributeMap, AtomicReferenceArray> updater =
AtomicReferenceFieldUpdater.newUpdater(DefaultAttributeMap.class, AtomicReferenceArray.class, "attributes");

//默认桶的大小
private static final int BUCKET_SIZE = 4;

//掩码 桶大小-1
private static final int MASK = BUCKET_SIZE - 1;

//延迟初始化,节约内存
// Initialize lazily to reduce memory consumption; updated by AtomicReferenceFieldUpdater above.
@SuppressWarnings("UnusedDeclaration")
private volatile AtomicReferenceArray<DefaultAttribute<?>> attributes;

@SuppressWarnings("unchecked")
@Override
public <T> Attribute<T> attr(AttributeKey<T> key) {
if (key == null) {
throw new NullPointerException("key");
}
AtomicReferenceArray<DefaultAttribute<?>> attributes = this.attributes;

//当attributes为空时则创建它,默认数组长度4
if (attributes == null) {
//没有使用ConcurrentHashMap为了节约内存
// Not using ConcurrentHashMap due to high memory consumption.
attributes = new AtomicReferenceArray<DefaultAttribute<?>>(BUCKET_SIZE);

//原子方式更新attributes,如果attributes为null则把新创建的对象赋值
//原子方式更新解决了并发赋值问题
if (!updater.compareAndSet(this, null, attributes)) {
attributes = this.attributes;
}
}

//根据key计算下标
int i = index(key);

//返回attributes数组中的第一个元素
DefaultAttribute<?> head = attributes.get(i);

//头部为空说明第一次添加,这个方法可能多个线程同时调用,因为判断head全部为null
if (head == null) {
// No head exists yet which means we may be able to add the attribute without synchronization and just
// use compare and set. At worst we need to fallback to synchronization and waste two allocations.

//创建一个空对象为链表结构的起点
head = new DefaultAttribute();

//创建一个attr对象,把head传进去
DefaultAttribute<T> attr = new DefaultAttribute<T>(head, key);

//链表头head的next = attr
head.next = attr;
//attr的prev = head
attr.prev = head;

//给数组i位置赋值,这里用compareAndSet原子更新方法解决并发问题
//只有i位置为null能够设置成功,且只有一个线程能设置成功
if (attributes.compareAndSet(i, null, head)) {
//设置成功后返回attr
// we were able to add it so return the attr right away
return attr;
} else {
//设置失败的,说明数组i位置已经被其它线程赋值
//所以要把head重新赋值,不能用上面new出来的head,需要拿到之前线程设置进去的head
head = attributes.get(i);
}
}

//对head同步加锁
synchronized (head) {
//curr 赋值为head head为链表结构的第一个变量
DefaultAttribute<?> curr = head;
for (;;) {
//依次获取next
DefaultAttribute<?> next = curr.next;
//next==null,说明curr为最后一个元素
if (next == null) {
//创建一个新对象传入head和key
DefaultAttribute<T> attr = new DefaultAttribute<T>(head, key);
//curr后面指向attr
curr.next = attr;
//attr的前面指向curr
attr.prev = curr;
//返回新对象
return attr;
}

//如果next的key等于传入的key,并且没有被移除
if (next.key == key && !next.removed) {
//这直接返回next
return (Attribute<T>) next;
}
//否则把curr变量指向下一个元素
curr = next;
}
}
}

@Override
public <T> boolean hasAttr(AttributeKey<T> key) {
if (key == null) {
throw new NullPointerException("key");
}

//attributes为null直接返回false
AtomicReferenceArray<DefaultAttribute<?>> attributes = this.attributes;
if (attributes == null) {
// no attribute exists
return false;
}

//计算数组下标
int i = index(key);

//获取头 为空直接返回false
DefaultAttribute<?> head = attributes.get(i);
if (head == null) {
// No attribute exists which point to the bucket in which the head should be located
return false;
}

//对head同步加锁
// We need to synchronize on the head.
synchronized (head) {
// Start with head.next as the head itself does not store an attribute.
//从head的下一个开始,因为head不存储元素
DefaultAttribute<?> curr = head.next;

//为null说明没有节点了
while (curr != null) {
//key一致并且没有被移除则返回true
if (curr.key == key && !curr.removed) {
return true;
}
//curr指向下一个
curr = curr.next;
}
return false;
}
}

private static int index(AttributeKey<?> key) {
//与掩码&运算,数值肯定<=mask 正好是数组下标
return key.id() & MASK;
}
}