All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.thimbleware.jmemcached.LocalCacheElement Maven / Gradle / Ivy

/**
 *  Copyright 2008 ThimbleWare Inc.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.thimbleware.jmemcached;

import com.thimbleware.jmemcached.util.BufferUtils;
import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.nio.ByteBuffer;


/**
 * Represents information about a cache entry.
 */
public final class LocalCacheElement implements CacheElement {
    private long expire; // uint
    private int flags;
    private ChannelBuffer data;
    private Key key;
    private long casUnique = 0L;
    private boolean blocked = false;
    private long blockedUntil;

    public LocalCacheElement() {
    }

    public LocalCacheElement(Key key) {
        this.key = key;
    }

    public LocalCacheElement(Key key, int flags, long expire, long casUnique) {
        this.key = key;
        this.flags = flags;
        this.expire = expire;
        this.casUnique = casUnique;
    }

    /**
     * @return the current time in seconds
     */
    public static int Now() {
        return (int) (System.currentTimeMillis() / 1000);
    }

    public int size() {
        return getData().capacity();
    }

    public LocalCacheElement append(LocalCacheElement appendElement) {
        int newLength = size() + appendElement.size();
        LocalCacheElement appendedElement = new LocalCacheElement(getKey(), getFlags(), getExpire(), 0L);
        ChannelBuffer appended = ChannelBuffers.buffer(newLength);
        ChannelBuffer existing = getData();
        ChannelBuffer append = appendElement.getData();

        appended.writeBytes(existing);
        appended.writeBytes(append);

        appended.readerIndex(0);

        existing.readerIndex(0);
        append.readerIndex(0);

        appendedElement.setData(appended);
        appendedElement.setCasUnique(appendedElement.getCasUnique() + 1);

        return appendedElement;
    }

    public LocalCacheElement prepend(LocalCacheElement prependElement) {
        int newLength = size() + prependElement.size();

        LocalCacheElement prependedElement = new LocalCacheElement(getKey(), getFlags(), getExpire(), 0L);
        ChannelBuffer prepended = ChannelBuffers.buffer(newLength);
        ChannelBuffer prepend = prependElement.getData();
        ChannelBuffer existing = getData();

        prepended.writeBytes(prepend);
        prepended.writeBytes(existing);

        existing.readerIndex(0);
        prepend.readerIndex(0);

        prepended.readerIndex(0);

        prependedElement.setData(prepended);
        prependedElement.setCasUnique(prependedElement.getCasUnique() + 1);

        return prependedElement;
    }

    public static class IncrDecrResult {
        long oldValue;
        LocalCacheElement replace;

        public IncrDecrResult(long oldValue, LocalCacheElement replace) {
            this.oldValue = oldValue;
            this.replace = replace;
        }
    }

    public IncrDecrResult add(long mod) {
        // TODO handle parse failure!
        long modVal = BufferUtils.atol(getData()) + mod; // change value
        if (modVal < 0) {
            modVal = 0;

        } // check for underflow

        ChannelBuffer newData = BufferUtils.ltoa(modVal);

        LocalCacheElement replace = new LocalCacheElement(getKey(), getFlags(), getExpire(), 0L);
        replace.setData(newData);
        replace.setCasUnique(replace.getCasUnique() + 1);

        return new IncrDecrResult(modVal, replace);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        LocalCacheElement that = (LocalCacheElement) o;

        if (blocked != that.blocked) return false;
        if (blockedUntil != that.blockedUntil) return false;
        if (casUnique != that.casUnique) return false;
        if (expire != that.expire) return false;
        if (flags != that.flags) return false;
        if (data != null ? !data.equals(that.data) : that.data != null) return false;
        if (key != null ? !key.equals(that.key) : that.key != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = (int) (expire ^ (expire >>> 32));
        result = 31 * result + flags;
        result = 31 * result + (data != null ? data.hashCode() : 0);
        result = 31 * result + (key != null ? key.hashCode() : 0);
        result = 31 * result + (int) (casUnique ^ (casUnique >>> 32));
        result = 31 * result + (blocked ? 1 : 0);
        result = 31 * result + (int) (blockedUntil ^ (blockedUntil >>> 32));
        return result;
    }

    public static LocalCacheElement key(Key key) {
        return new LocalCacheElement(key);
    }

    /**
     * uint
     */
    public long getExpire() {
        return expire;
    }
    
    public void setExpire(long expire){
	this.expire = expire;
    }

    public int getFlags() {
        return flags;
    }

    public ChannelBuffer getData() {
        data.readerIndex(0);
        return data;
    }

    public Key getKey() {
        return key;
    }

    public long getCasUnique() {
        return casUnique;
    }

    public boolean isBlocked() {
        return blocked;
    }

    public long getBlockedUntil() {
        return blockedUntil;
    }

    public void setCasUnique(long casUnique) {
        this.casUnique = casUnique;
    }

    public void block(long blockedUntil) {
        this.blocked = true;
        this.blockedUntil = blockedUntil;
    }


    public void setData(ChannelBuffer data) {
        data.readerIndex(0);
        this.data = data;
    }

    public static LocalCacheElement readFromBuffer(ChannelBuffer in) {
        int bufferSize = in.readInt();
        long expiry = in.readUnsignedInt();
        int keyLength = in.readInt();
        ChannelBuffer key = in.slice(in.readerIndex(), keyLength);
        in.skipBytes(keyLength);
        LocalCacheElement localCacheElement = new LocalCacheElement(new Key(key));

        localCacheElement.expire = expiry;
        localCacheElement.flags = in.readInt();

        int dataLength = in.readInt();
        localCacheElement.data = in.slice(in.readerIndex(), dataLength);
        in.skipBytes(dataLength);

        localCacheElement.casUnique = in.readInt();
        localCacheElement.blocked = in.readByte() == 1;
        localCacheElement.blockedUntil = in.readLong();

        return localCacheElement;
    }

    public int bufferSize() {
        return 4 + 4 + 4 + key.bytes.capacity() + 4 + 4 + 4 + data.capacity() + 8 + 1 + 8;
    }

    public void writeToBuffer(ChannelBuffer out) {
        out.writeInt(bufferSize());
        out.writeInt((int)expire);
        out.writeInt(key.bytes.capacity());
        out.writeBytes(key.bytes);
        out.writeInt(flags);
        out.writeInt(data.capacity());
        out.writeBytes(data);
        out.writeLong(casUnique);
        out.writeByte(blocked ? 1 : 0);
        out.writeLong(blockedUntil);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy