深入理解Ehcache系列(六)

         Ehcache中可以使用Cache的put(Element element)方来缓存对象。在执行的开始和结束时并调用了putObserver.begin()和putObserver.end(PutOutcome.XXX)方法。然后接着需要检查Cache的Alive状态, 检查被添加元素是否合法,检查是否支持写操作,最后再执行compoundStore.put(element)方法来缓存对象。

public final void put(Element element) throws IllegalArgumentException, IllegalStateException,
            CacheException {
        put(element, false);
    }

     

         compoundStroe是一个Store接口的具体实现,它的变量申明如下。

    /**
     * The {@link import net.sf.ehcache.store.Store} of this {@link Cache}.
     */
    private volatile Store compoundStore;

 


        还是照例先贴出Store的UML类图,因为它能更直接,更抽象的表达原作者的设计思路。

 123524_9Xtc_1050156.png


        Cache中数据存取操作大部分都是基于MemoryStore实例的。MemoryStore实例中数据通过SelectableConcurrentHashMap的实例进行存储。

          /**
     * Map where items are stored by key.
     */
    private final SelectableConcurrentHashMap map;


      public boolean put(final Element element) throws CacheException {
        if (element == null) {
            return false;
        }
        if (searchManager != null) {
            searchManager.put(cache.getName(), -1, element, null, attributeExtractors, cache.getCacheConfiguration().getDynamicExtractor());
        }
        putObserver.begin();
        long delta = poolAccessor.add(element.getObjectKey(), element.getObjectValue(), map.storedObject(element), storePinned);
        if (delta > -1) {
            Element old = map.put(element.getObjectKey(), element, delta);
            checkCapacity(element);
            if (old == null) {
                putObserver.end(PutOutcome.ADDED);
                return true;
            } else {
                putObserver.end(PutOutcome.UPDATED);
                return false;
            }
        } else {
            notifyDirectEviction(element);
            putObserver.end(PutOutcome.ADDED);
            return true;
        }
    }

         核心操作为:

    
Element old = map.put(element.getObjectKey(), element, delta);

           

 public Element put(Object key, Element element, long sizeOf) {
        int hash = hash(key.hashCode());
        return segmentFor(hash).put(key, hash, element, sizeOf, false, true);
    }


          先通过segmentFor,根据key找到存储数据的Segment,然后再在所在的Segment中进行put

125556_goaI_1050156.png

          Segment的put操作会把Element保存在一个HashEntry数组中。保存的时候会先Check是否存在oldElement判断是不否需要复盖。

private volatile HashEntry[] table;

    


    详细的请参照如下,在后面我会挑选重要部分,同大家一起探讨。

    Element put(Object key, int hash, Element element, boolean onlyIfAbsent, boolean faulted) {
        boolean installed = false;
        DiskSubstitute encoded = disk.create(element);
        final long incomingHeapSize = onHeapPoolAccessor.add(key, encoded, NULL_HASH_ENTRY, cachePinned || faulted);
        if (incomingHeapSize < 0) {
            LOG.debug("put failed to add on heap");
            evictionObserver.end(EvictionOutcome.SUCCESS);
            cacheEventNotificationService.notifyElementEvicted(element, false);
            return null;
        } else {
            LOG.debug("put added {} on heap", incomingHeapSize);
            encoded.onHeapSize = incomingHeapSize;
        }
        writeLock().lock();
        try {
            // ensure capacity
            if (count + 1 > threshold) {
                rehash();
            }
            HashEntry[] tab = table;
            int index = hash & (tab.length - 1);
            HashEntry first = tab[index];
            HashEntry e = first;
            while (e != null && (e.hash != hash || !key.equals(e.key))) {
                e = e.next;
            }
            Element oldElement;
            if (e != null) {
                DiskSubstitute onDiskSubstitute = e.element;
                if (!onlyIfAbsent) {
                    e.element = encoded;
                    installed = true;
                    oldElement = decode(onDiskSubstitute);
                    free(onDiskSubstitute);
                    final long existingHeapSize = onHeapPoolAccessor.delete(onDiskSubstitute.onHeapSize);
                    LOG.debug("put updated, deleted {} on heap", existingHeapSize);
                    if (onDiskSubstitute instanceof DiskStorageFactory.DiskMarker) {
                        final long existingDiskSize = onDiskPoolAccessor.delete(((DiskStorageFactory.DiskMarker) onDiskSubstitute).getSize());
                        LOG.debug("put updated, deleted {} on disk", existingDiskSize);
                    }
                    e.faulted.set(faulted);
                    cacheEventNotificationService.notifyElementUpdatedOrdered(oldElement, element);
                } else {
                    oldElement = decode(onDiskSubstitute);
                    free(encoded);
                    final long outgoingHeapSize = onHeapPoolAccessor.delete(encoded.onHeapSize);
                    LOG.debug("put if absent failed, deleted {} on heap", outgoingHeapSize);
                }
            } else {
                oldElement = null;
                ++modCount;
                tab[index] = new HashEntry(key, hash, first, encoded, new AtomicBoolean(faulted));
                installed = true;
                // write-volatile
                count = count + 1;
                cacheEventNotificationService.notifyElementPutOrdered(element);
            }
            return oldElement;
        } finally {
            writeLock().unlock();
            if (installed) {
                encoded.installed();
            }
        }
    }


转载于:https://my.oschina.net/zookeeper/blog/186226

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值