001/* 002 * JKNIV, utils - Helper utilities for jdk code. 003 * 004 * Copyright (C) 2017, the original author or authors. 005 * 006 * This library is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 2.1 of the License. 010 * 011 * This library is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public 017 * License along with this library; if not, write to the Free Software Foundation, Inc., 018 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 019 */ 020package net.sf.jkniv.cache; 021 022import java.util.concurrent.TimeUnit; 023 024import org.slf4j.Logger; 025import org.slf4j.LoggerFactory; 026 027import net.sf.jkniv.asserts.Assertable; 028import net.sf.jkniv.asserts.AssertsFactory; 029 030/* 031 032 no expiry - this means cache mappings will never expire, 033 time-to-live - this means cache mappings will expire after a fixed duration following their creation, 034 time-to-idle - this means cache mappings will expire after a fixed duration following the time they were last accessed. 035 036 */ 037/** 038 * Cache policy using concepts from Time to live (TTL) to limit the lifetime of data. 039 * 040 * @author Alisson Gomes 041 * @since 0.6.0 042 */ 043public class TTLCachePolicy implements CachePolicy 044{ 045 private static final Logger LOG = LoggerFactory.getLogger(TTLCachePolicy.class); 046 private static final Assertable notNull = AssertsFactory.getNotNull(); 047 048 private final static long KB_FACTOR = 1000; 049 private final static long KIB_FACTOR = 1024; 050 private final static long MB_FACTOR = 1000 * KB_FACTOR; 051 private final static long MIB_FACTOR = 1024 * KIB_FACTOR; 052 private final static long GB_FACTOR = 1000 * MB_FACTOR; 053 private final static long GIB_FACTOR = 1024 * MIB_FACTOR; 054 055 056 //private long timestamp; 057 private long ttl; // time-to-live 058 private long tti; // time-to-idle 059 private long size; 060 private long sizeof; 061 062 /** 063 * Build a policy with TTL as parameter to keep the objects alive in cache 064 * @param ttl time in seconds 065 */ 066 public TTLCachePolicy(long ttl) 067 { 068 this(ttl, DEFAULT_TTI); 069 } 070 071 /** 072 * Build a policy with TTL and TTI as parameter to keep the objects alive in cache 073 * @param ttl time-to-live in seconds 074 * @param tti time-to-idle in seconds 075 */ 076 public TTLCachePolicy(long ttl, long tti) 077 { 078 this(ttl, tti, TimeUnit.SECONDS); 079 } 080 081 /** 082 * Build a policy with TTL and TTI as parameter to keep the objects alive in cache 083 * @param ttl time-to-live in seconds 084 * @param tti time-to-idle in seconds 085 * @param unit time unit for TTL and TTI 086 */ 087 public TTLCachePolicy(long ttl, long tti, TimeUnit unit) 088 { 089 this(ttl, tti, unit, DEFAULT_SIZE, DEFAULT_SIZEOF+""); 090 } 091 092 /** 093 * Build a policy with TTL and TTI as parameter to keep the objects alive in cache 094 * @param ttl time-to-live in seconds 095 * @param tti time-to-idle in seconds 096 * @param size limit for number of object 097 * @param sizeof limit for size for sum of objects 098 */ 099 public TTLCachePolicy(long ttl, long tti, long size, String sizeof) 100 { 101 this(ttl, tti, TimeUnit.SECONDS, size, sizeof); 102 } 103 /** 104 * Build a policy with TTL and TTI as parameter to keep the objects alive in cache 105 * @param ttl time-to-live in seconds 106 * @param tti time-to-idle in seconds 107 * @param unit time unit for TTL and TTI 108 * @param size limit for number of object 109 * @param sizeof limit for size for sum of objects 110 */ 111 public TTLCachePolicy(long ttl, long tti, TimeUnit unit, long size, String sizeof) 112 { 113 notNull.verify(unit, sizeof); 114 this.ttl = unit.toMillis(ttl); 115 this.tti = unit.toMillis(tti); 116 this.size = size; 117 this.sizeof = toBytes(sizeof); 118 } 119 120 @Override 121 public boolean isAlive(long ttl) 122 { 123 if (this.ttl < 0) 124 return true; 125 126 return !expireTTL(ttl); 127 } 128 129 @Override 130 public boolean isAlive(long ttl, long tti) 131 { 132 if (this.ttl < 0) 133 return true; 134 135 if (expireTTL(ttl)) 136 return false; 137 138 if (this.tti < 0) 139 return true; 140 141 if (expireTTI(tti)) 142 return false; 143 144 return true; 145 } 146 147 private boolean expireTTL(long ttl) 148 { 149 boolean ret = ((ttl + this.ttl) <= System.currentTimeMillis()); 150 if(LOG.isDebugEnabled()) 151 LOG.debug("Cache Expire TTL[{}] timestamp data [{}] current [{}] resting = {} => {}", (ttl + this.ttl), ttl, System.currentTimeMillis(), (System.currentTimeMillis()-(ttl + this.ttl)), ret); 152 return ret; 153 } 154 155 private boolean expireTTI(long tti) 156 { 157 boolean ret = ((tti + this.tti) <= System.currentTimeMillis()); 158 if(LOG.isDebugEnabled()) 159 LOG.debug("Cache Expire TTI[{}] timestamp data [{}] current [{}] resting = {} => {}", (tti + this.tti), tti, System.currentTimeMillis(), (System.currentTimeMillis()-(tti + this.tti)), ret); 160 return ret; 161 } 162 163 // FIXME implements limit from CachePolicy 164 @Override 165 public long size() 166 { 167 return this.size; 168 } 169 170 // FIXME implements sizeof from CachePolicy 171 @Override 172 public long sizeof() 173 { 174 return this.sizeof; 175 } 176 177 @Override 178 public String toString() 179 { 180 return "TTLCachePolicy [ttl=" + ttl + ", tti=" + tti + ", size=" + size + ", sizeof=" + sizeof + "]"; 181 } 182 183 184 /** 185 * 186 * @param sizeof <size>[g|G|m|M|k|K] 187 * @return 188 */ 189 private long toBytes(String sizeof) 190 { 191 long bytes = -1L; // without sizeof limits 192 String sizeofNormalized = (sizeof != null ? sizeof.toLowerCase() : ""); 193 String sizeofNumber = (sizeof.length() > 1 ? sizeof.substring(0, sizeof.length()-1) : ""); 194 if (sizeofNormalized.endsWith("k")) 195 bytes = KIB_FACTOR * Long.valueOf(sizeofNumber); 196 else if (sizeofNormalized.endsWith("m")) 197 bytes = MIB_FACTOR * Long.valueOf(sizeofNumber); 198 else if (sizeofNormalized.endsWith("g")) 199 bytes = GIB_FACTOR * Long.valueOf(sizeofNumber); 200 else if (sizeofNormalized.length() > 0) 201 bytes = Long.valueOf(sizeofNormalized); 202 203 return bytes; 204 } 205}