Atrinik Server 2.5
server/cache.c
Go to the documentation of this file.
00001 /************************************************************************
00002 *            Atrinik, a Multiplayer Online Role Playing Game            *
00003 *                                                                       *
00004 *    Copyright (C) 2009-2011 Alex Tokar and Atrinik Development Team    *
00005 *                                                                       *
00006 * Fork from Daimonin (Massive Multiplayer Online Role Playing Game)     *
00007 * and Crossfire (Multiplayer game for X-windows).                       *
00008 *                                                                       *
00009 * This program is free software; you can redistribute it and/or modify  *
00010 * it under the terms of the GNU General Public License as published by  *
00011 * the Free Software Foundation; either version 2 of the License, or     *
00012 * (at your option) any later version.                                   *
00013 *                                                                       *
00014 * This program is distributed in the hope that it will be useful,       *
00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00017 * GNU General Public License for more details.                          *
00018 *                                                                       *
00019 * You should have received a copy of the GNU General Public License     *
00020 * along with this program; if not, write to the Free Software           *
00021 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.             *
00022 *                                                                       *
00023 * The author can be reached at admin@atrinik.org                        *
00024 ************************************************************************/
00025 
00056 #include <global.h>
00057 
00059 static cache_struct *cache = NULL;
00061 static size_t num_cache = 0;
00062 
00065 static int cache_compare(const void *one, const void *two)
00066 {
00067     cache_struct *one_cache = (cache_struct *) one;
00068     cache_struct *two_cache = (cache_struct *) two;
00069 
00070     if (one == NULL)
00071     {
00072         return -1;
00073     }
00074     else if (two == NULL)
00075     {
00076         return 1;
00077     }
00078 
00079     if (one_cache->key < two_cache->key)
00080     {
00081         return -1;
00082     }
00083     else if (one_cache->key > two_cache->key)
00084     {
00085         return 1;
00086     }
00087     else
00088     {
00089         return 0;
00090     }
00091 }
00092 
00097 cache_struct *cache_find(shstr *key)
00098 {
00099     cache_struct bkey;
00100 
00101     /* Sanity. */
00102     if (!cache || !num_cache || !key)
00103     {
00104         return NULL;
00105     }
00106 
00107     /* Attempt to find the cache entry. */
00108     bkey.key = key;
00109     return bsearch((void *) &bkey, cache, num_cache, sizeof(cache_struct), cache_compare);
00110 }
00111 
00119 int cache_add(const char *key, void *ptr, uint32 flags)
00120 {
00121     size_t i, ii;
00122     shstr *sh_key = add_string(key);
00123 
00124     /* Sanity. */
00125     if (!ptr || cache_find(sh_key))
00126     {
00127         return 0;
00128     }
00129 
00130     /* Increase the array's size. */
00131     cache = realloc(cache, sizeof(cache_struct) * (num_cache + 1));
00132 
00133     /* Now, insert the cache into the correct spot in the array. */
00134     for (i = 0; i < num_cache; i++)
00135     {
00136         if (cache[i].key > sh_key)
00137         {
00138             break;
00139         }
00140     }
00141 
00142     /* If this is not the special case of insertion at the last point, then shift everything. */
00143     for (ii = num_cache; ii > i; ii--)
00144     {
00145         cache[ii] = cache[ii - 1];
00146         /* Increase the ID, as it's getting moved upwards. */
00147         cache[ii].id++;
00148     }
00149 
00150     /* Store the values. */
00151     cache[i].key = sh_key;
00152     cache[i].ptr = ptr;
00153     cache[i].flags = flags;
00154     cache[i].id = i;
00155     num_cache++;
00156 
00157     return 1;
00158 }
00159 
00164 int cache_remove(shstr *key)
00165 {
00166     cache_struct *entry = cache_find(key);
00167     size_t i;
00168 
00169     if (!entry)
00170     {
00171         return 0;
00172     }
00173 
00174     /* The entry wants global events, so send one about it being removed. */
00175     if (entry->flags & CACHE_FLAG_GEVENT)
00176     {
00177         trigger_global_event(GEVENT_CACHE_REMOVED, entry->ptr, (uint32 *) &entry->flags);
00178     }
00179 
00180     /* Does it want to be freed automatically? */
00181     if (entry->flags & CACHE_FLAG_AUTOFREE)
00182     {
00183         free(entry->ptr);
00184     }
00185 
00186     /* Shift the entries. */
00187     for (i = entry->id + 1; i < num_cache; i++)
00188     {
00189         cache[i - 1] = cache[i];
00190         /* Moving downwards, decrease ID. */
00191         cache[i - 1].id--;
00192     }
00193 
00194     /* Decrease the array's size. */
00195     cache = realloc(cache, sizeof(cache_struct) * (num_cache - 1));
00196     num_cache--;
00197 
00198     return 1;
00199 }
00200 
00203 void cache_remove_all()
00204 {
00205     /* Keep removing until there's nothing left. */
00206     while (num_cache)
00207     {
00208         cache_remove(cache[0].key);
00209     }
00210 }
00211 
00215 void cache_remove_by_flags(uint32 flags)
00216 {
00217     size_t i;
00218 
00219     /* Search for matching entries, and remove them. */
00220     for (i = 0; i < num_cache; i++)
00221     {
00222         if (cache[i].flags & flags)
00223         {
00224             cache_remove(cache[i].key);
00225             i--;
00226         }
00227     }
00228 }