From 62c6acd629abe3b12b84fafc4b52326622bbcd26 Mon Sep 17 00:00:00 2001 From: Dmitrii Zagorodnov Date: Tue, 27 Jan 2009 02:57:41 -0800 Subject: [PATCH] max cache size support --- node/handlers.c | 1 + storage/Makefile | 6 + storage/storage.c | 492 ++++++++++++++++++++++++++++++++++------------ storage/storage.h | 2 + util/eucalyptus.h | 3 + util/misc.c | 92 ++++++++- util/misc.h | 2 + 7 files changed, 472 insertions(+), 126 deletions(-) diff --git a/node/handlers.c b/node/handlers.c index 2c4241a446c..f51e0040228 100644 --- a/node/handlers.c +++ b/node/handlers.c @@ -942,6 +942,7 @@ int doDescribeResource (ncMetadata *meta, char *resourceType, ncResource **outRe int sum_cores = 0; /* for known domains: sum of requested cores */ logprintfl (EUCAINFO, "doDescribeResource() invoked\n"); + LogprintfCache (); /* print cache contents */ * outRes = NULL; error = init_config(); diff --git a/storage/Makefile b/storage/Makefile index 6e58160ed36..1746e501103 100644 --- a/storage/Makefile +++ b/storage/Makefile @@ -17,9 +17,15 @@ Wclient: Makefile Wclient.c ../util/euca_auth.o ../util/misc.o walrus.o walrus.o: walrus.c walrus.h $(CC) $(CFLAGS) $(INCLUDES) -c walrus.c +test: test.c storage.h storage.o ../util/misc.o ../util/data.o ../util/ipc.o ../util/euca_auth.o walrus.o + $(CC) $(CFLAGS) $(INCLUDES) test.c storage.o ../util/misc.o ../util/data.o ../util/ipc.o ../util/euca_auth.o walrus.o $(STORAGE_LIBS) -o test + .c.o: $(CC) -c $(CFLAGS) $(INCLUDES) $< +../util/ipc.o: ../util/ipc.c ../util/ipc.h ../util/eucalyptus.h + make -C ../util + ../util/misc.o: ../util/misc.c ../util/misc.h ../util/eucalyptus.h make -C ../util diff --git a/storage/storage.c b/storage/storage.c index fd35a1c3408..6bec1b3fbd6 100644 --- a/storage/storage.c +++ b/storage/storage.c @@ -33,6 +33,10 @@ static char *sc_instance_path = ""; static int scConfigInit=0; static sem * sc_sem; +/* in MB */ +static long long cache_size_mb = DEFAULT_NC_CACHE_SIZE; +static long long cache_free_mb = DEFAULT_NC_CACHE_SIZE; + int scInitConfig (void) { struct stat mystat; @@ -61,6 +65,12 @@ int scInitConfig (void) sc_instance_path = strdup (s); free (s); } + + if (get_conf_var(config, CONFIG_NC_CACHE_SIZE, &s)>0){ + cache_size_mb = atoll (s); + cache_free_mb = cache_size_mb; + free (s); + } } snprintf(add_key_command_path, BUFSIZE, EUCALYPTUS_ADD_KEY, home, home, home); @@ -131,111 +141,134 @@ ncInstance * scRecoverInstanceInfo (const char *instanceId) return instance; } -/* perform integrity check on instances directory, including the cache: - * remove any files from non-running Eucalyptus instances, delete files - * from cache that are not complete, return the amount of bytes used up by - * everything - */ -long long scFSCK (bunchOfInstances ** instances) -{ - long long total_size = 0; - struct stat mystat; +typedef struct cache_entry_t { + char path [BUFSIZE]; + long long size_mb; + struct cache_entry_t * next; + struct cache_entry_t * prev; +} cache_entry; - if (instances==NULL) return -1; - - logprintfl (EUCAINFO, "checking the integrity of instances directory (%s)\n", sc_instance_path); +static cache_entry * cache_head = NULL; - /* let us not 'rm -rf /' accidentally */ - if (strlen(sc_instance_path)<2 || - sc_instance_path[0]!='/' ) { - logprintfl (EUCAFATAL, "error: instances directory cannot be /, sorry\n"); - return -1; - } +static void add_to_cache (const char * cached_path, const long long file_size_bytes) +{ + long long file_size_mb = file_size_bytes/MEGABYTE; - if (stat (sc_instance_path, &mystat) < 0) { - logprintfl (EUCAFATAL, "error: could not stat %s\n", sc_instance_path); - return -1; + cache_entry * e = malloc (sizeof(cache_entry)); + if (e==NULL) { + logprintfl (EUCAFATAL, "error: out of memory in add_to_cache()\n"); + return; } - total_size += mystat.st_size; - DIR * insts_dir; - if ((insts_dir=opendir(sc_instance_path))==NULL) { - logprintfl (EUCAFATAL, "error: could not open instances directory %s\n", sc_instance_path); - return -1; + strncpy (e->path, cached_path, BUFSIZE); + e->size_mb = file_size_mb; + e->next = NULL; + e->prev = NULL; + + // add at the end + cache_entry ** pp; + cache_entry * p = NULL; + for ( pp = & cache_head; * pp != NULL; pp = & ((* pp)->next)) p = * pp; + if ( p ) { + e->prev = p; } + * pp = e; - /*** run through all users ***/ + cache_free_mb -= file_size_mb; +} - char * cache_path = NULL; - struct dirent * inst_dir_entry; - while ((inst_dir_entry=readdir(insts_dir))!=NULL) { - char * uname = inst_dir_entry->d_name; - char user_path [BUFSIZE]; - struct dirent * user_dir_entry; - DIR * user_dir; +void LogprintfCache (void) +{ + struct stat mystat; + cache_entry * e; + if (cache_head) { + logprintfl (EUCAINFO, "cached images (free=%d of %dMB):\n", cache_free_mb, cache_size_mb); + } else { + logprintfl (EUCAINFO, "cached images (free=%d of %dMB): none\n", cache_free_mb, cache_size_mb); + } + for ( e = cache_head; e; e=e->next) { + bzero (&mystat, sizeof (mystat)); + stat (e->path, &mystat); + logprintfl (EUCAINFO, "\t%5dMB %8dsec %s\n", e->size_mb, mystat.st_mtime, e->path); + } +} - if (!strcmp(".", uname) || - !strcmp("..", uname)) - continue; +/* Returns 1 if there is space in the cache for the image, + * purging the cache in LRU fashion, if necessary. + * The function assumes the image is not in the cache already */ +static int ok_to_cache (const char * cached_path, const long long file_size_bytes) +{ + long long file_size_mb = file_size_bytes/MEGABYTE; - snprintf (user_path, BUFSIZE, "%s/%s", sc_instance_path, uname); - if ((user_dir=opendir(user_path))==NULL) { - logprintfl (EUCAWARN, "warning: unopeneable directory %s\n", user_path); - continue; - } + if (file_size_mb > cache_size_mb) return 0; - /*** run through all instances of a user ***/ - while ((user_dir_entry=readdir(user_dir))!=NULL) { - char * iname = user_dir_entry->d_name; - - if (!strcmp(".", iname) || - !strcmp("..", iname)) - continue; - - char instance_path [BUFSIZE]; - snprintf (instance_path, BUFSIZE, "%s/%s", user_path, iname); - - if (!strcmp("cache", iname) && - !strcmp(EUCALYPTUS_ADMIN, uname)) { /* cache is in admin's dir */ - cache_path = strdup (instance_path); - continue; + while (file_size_mb > cache_free_mb) { + time_t oldest_mtime = time (NULL) + 1; + off_t oldest_size = 0; + cache_entry * oldest_entry = NULL; + struct stat mystat; + cache_entry * e; + for ( e = cache_head; e; e=e->next) { + if (stat (e->path, &mystat)<0) { + logprintfl (EUCAERROR, "error: ok_to_cache() can't stat %s\n", cached_path); + return 0; } - - /* spare directories of running instances, but count their usage */ - if (find_instance (instances, iname)) { - int bytes = dir_size (instance_path); - if (bytes>0) { - logprintfl (EUCAINFO, "- running instance %s directory, size=%d\n", iname, bytes); - total_size += bytes; - } else if (bytes==0) { - logprintfl (EUCAWARN, "warning: empty instance directory %s\n", instance_path); - } else { - logprintfl (EUCAWARN, "warning: non-standard instance directory %s\n", instance_path); - } - continue; + if (mystat.st_mtimesize_mb; /* (mystat.st_size doesn't include digest) */ + oldest_entry = e; + } else { + if (mystat.st_mtime==oldest_mtime) { + /* smaller ones get purged first */ + if (oldest_size > e->size_mb) { + oldest_size = e->size_mb; + oldest_entry = e; + } + } } + } - /* looks good - destroy it */ - if (vrun ("rm -rf %s", instance_path)) { - logprintfl (EUCAWARN, "warning: failed to remove %s\n", instance_path); + if ( oldest_entry ) { // remove it + logprintfl (EUCAINFO, "purging from cache image %s\n", oldest_entry->path); + if ( oldest_entry->next ) { + oldest_entry->next->prev = oldest_entry->prev; + } + if ( oldest_entry->prev ) { + oldest_entry->prev->next = oldest_entry->next; + } else { + cache_head = oldest_entry->next; + } + if ( unlink (oldest_entry->path) != 0 ) { // should allow open descriptors to complete + logprintfl (EUCAERROR, "error: failed to unlink file %s (%s)\n", oldest_entry->path, strerror (errno)); } + char digest_path [BUFSIZE]; + snprintf (digest_path, BUFSIZE, "%s-digest", oldest_entry->path); + unlink (digest_path); + cache_free_mb += oldest_entry->size_mb; + free (oldest_entry); + } else { + logprintfl (EUCAERROR, "error: cannot find oldest entry in cache\n"); + return 0; } - closedir (user_dir); } - closedir (insts_dir); - - /*** scan the cache ***/ + add_to_cache (cached_path, file_size_bytes); + return 1; +} +static long long init_cache (const char * cache_path) +{ + long long total_size = 0; + logprintfl (EUCAINFO, "checking the integrity of the cache directory (%s)\n", cache_path); - + if (cache_path==NULL) { logprintfl (EUCAINFO, "no cache directory yet\n"); return total_size; } + struct stat mystat; if (stat (cache_path, &mystat) < 0) { logprintfl (EUCAFATAL, "error: could not stat %s\n", cache_path); - free (cache_path); return -1; } total_size += mystat.st_size; @@ -243,7 +276,6 @@ long long scFSCK (bunchOfInstances ** instances) DIR * cache_dir; if ((cache_dir=opendir(cache_path))==NULL) { logprintfl (EUCAFATAL, "errror: could not open cache directory %s\n", cache_path); - free (cache_path); return -1; } @@ -283,6 +315,7 @@ long long scFSCK (bunchOfInstances ** instances) if (!strcmp(".", name) || !strcmp("..", name)) continue; + image_files++; char filepath [BUFSIZE]; @@ -309,25 +342,191 @@ long long scFSCK (bunchOfInstances ** instances) strncpy (X_digest, name, BUFSIZE); } } - - if (image_files != 2 || strncmp (X, X_digest, BUFSIZE) != 0 ) { - logprintfl (EUCAERROR, "error: inconsistent state of cached image %s, deleting it\n", image_name); - if (vrun ("rm -rf %s", image_path)) { - logprintfl (EUCAWARN, "warning: failed to remove %s\n", image_path); - } - } else { - if (image_size>0) { - logprintfl (EUCAINFO, "- cached image %s directory, size=%d\n", image_name, image_size); - total_size += image_size; + + if (image_files > 0) { /* ignore empty directories */ + if (image_files != 2 || strncmp (X, X_digest, BUFSIZE) != 0 ) { + logprintfl (EUCAERROR, "error: inconsistent state of cached image %s, deleting it\n", image_name); + if (vrun ("rm -rf %s", image_path)) { + logprintfl (EUCAWARN, "warning: failed to remove %s\n", image_path); + } } else { - logprintfl (EUCAWARN, "warning: empty cached image directory %s\n", image_path); + char filepath [BUFSIZE]; + snprintf (filepath, BUFSIZE, "%s/%s", image_path, X); + if (image_size>0) { + logprintfl (EUCAINFO, "- cached image %s directory, size=%d\n", image_name, image_size); + total_size += image_size; + add_to_cache (filepath, image_size); + } else { + logprintfl (EUCAWARN, "warning: empty cached image directory %s\n", image_path); + } } } } closedir (cache_dir); + + return total_size; +} + +#define F1 "/tmp/improbable-cache-file-1" +#define F2 "/tmp/improbable-cache-file-2" +#define F3 "/tmp/improbable-cache-file-3" +#define F4 "/tmp/improbable-cache-file-4" +#define F5 "/tmp/improbable-cache-file-5" +#define RM_CMD "rm -rf /tmp/improbable-cache-file-?" + +int test_cache (void) +{ + int error = 0; + + /* save the current values */ + long long saved_size = cache_size_mb; + long long saved_free = cache_free_mb; + cache_entry * saved_head = cache_head; + + cache_size_mb = 10; + cache_free_mb = 10; + cache_head = NULL; + + touch (F1); + if (ok_to_cache (F1, 3*MEGABYTE)!=1) { error= 1; goto out; } + LogprintfCache(); + sleep (1); + + touch (F2); + add_to_cache (F2, 3*MEGABYTE); + LogprintfCache(); + sleep (1); + + touch (F3); + if (ok_to_cache (F3, 11*MEGABYTE)!=0) { error = 2; goto out; } + if (ok_to_cache (F3, 7*MEGABYTE)!=1) { error = 3; goto out; } + LogprintfCache(); + + touch (F4); + if (ok_to_cache (F4, 4*MEGABYTE)!=1) { error = 4; goto out; } + touch (F5); + if (ok_to_cache (F5, 6*MEGABYTE)!=1) { error = 5; goto out; } + LogprintfCache(); + + touch (F3); + add_to_cache (F3, 3*MEGABYTE); + touch (F2); + add_to_cache (F2, 5*MEGABYTE); + LogprintfCache(); + + touch (F1); + if (ok_to_cache (F1, 1*MEGABYTE)!=1) { error = 6; goto out; } + LogprintfCache(); + +out: + cache_size_mb = saved_size; + cache_free_mb = saved_free; + cache_head = saved_head; + system (RM_CMD); + return error; +} + +/* perform integrity check on instances directory, including the cache: + * remove any files from non-running Eucalyptus instances, delete files + * from cache that are not complete, return the amount of bytes used up by + * everything + */ +long long scFSCK (bunchOfInstances ** instances) +{ + long long total_size = 0; + struct stat mystat; + + if (instances==NULL) return -1; + + logprintfl (EUCAINFO, "checking the integrity of instances directory (%s)\n", sc_instance_path); + + /* let us not 'rm -rf /' accidentally */ + if (strlen(sc_instance_path)<2 || + sc_instance_path[0]!='/' ) { + logprintfl (EUCAFATAL, "error: instances directory cannot be /, sorry\n"); + return -1; + } + + if (stat (sc_instance_path, &mystat) < 0) { + logprintfl (EUCAFATAL, "error: could not stat %s\n", sc_instance_path); + return -1; + } + total_size += mystat.st_size; + + DIR * insts_dir; + if ((insts_dir=opendir(sc_instance_path))==NULL) { + logprintfl (EUCAFATAL, "error: could not open instances directory %s\n", sc_instance_path); + return -1; + } + + /*** run through all users ***/ + + char * cache_path = NULL; + struct dirent * inst_dir_entry; + while ((inst_dir_entry=readdir(insts_dir))!=NULL) { + char * uname = inst_dir_entry->d_name; + char user_path [BUFSIZE]; + struct dirent * user_dir_entry; + DIR * user_dir; + + if (!strcmp(".", uname) || + !strcmp("..", uname)) + continue; + + snprintf (user_path, BUFSIZE, "%s/%s", sc_instance_path, uname); + if ((user_dir=opendir(user_path))==NULL) { + logprintfl (EUCAWARN, "warning: unopeneable directory %s\n", user_path); + continue; + } + + /*** run through all instances of a user ***/ + while ((user_dir_entry=readdir(user_dir))!=NULL) { + char * iname = user_dir_entry->d_name; + + if (!strcmp(".", iname) || + !strcmp("..", iname)) + continue; + + char instance_path [BUFSIZE]; + snprintf (instance_path, BUFSIZE, "%s/%s", user_path, iname); + + if (!strcmp("cache", iname) && + !strcmp(EUCALYPTUS_ADMIN, uname)) { /* cache is in admin's dir */ + cache_path = strdup (instance_path); + continue; + } + + /* spare directories of running instances, but count their usage */ + if (find_instance (instances, iname)) { + int bytes = dir_size (instance_path); + if (bytes>0) { + logprintfl (EUCAINFO, "- running instance %s directory, size=%d\n", iname, bytes); + total_size += bytes; + } else if (bytes==0) { + logprintfl (EUCAWARN, "warning: empty instance directory %s\n", instance_path); + } else { + logprintfl (EUCAWARN, "warning: non-standard instance directory %s\n", instance_path); + } + continue; + } + + /* looks good - destroy it */ + if (vrun ("rm -rf %s", instance_path)) { + logprintfl (EUCAWARN, "warning: failed to remove %s\n", instance_path); + } + } + closedir (user_dir); + } + closedir (insts_dir); + + /*** scan the cache ***/ + long long cache_bytes = init_cache (cache_path); free (cache_path); + if (cache_bytes < 0) { + return -1; + } - return total_size; + return total_size + cache_bytes; } const char * scGetInstancePath(void) @@ -433,27 +632,30 @@ static int wait_for_file (const char * appear, const char * disappear, const int static int get_cached_file (const char * user_id, const char * url, const char * file_id, const char * instance_id, const char * file_name, char * file_path) { - char cached_dir [BUFSIZE]; - char cached_path [BUFSIZE]; - char staging_path [BUFSIZE]; - char digest_path [BUFSIZE]; + char tmp_digest_path [BUFSIZE]; + char cached_dir [BUFSIZE]; + char cached_path [BUFSIZE]; + char staging_path [BUFSIZE]; + char digest_path [BUFSIZE]; - snprintf (file_path, BUFSIZE, "%s/%s/%s/%s", sc_instance_path, user_id, instance_id, file_name); - snprintf (cached_dir, BUFSIZE, "%s/%s/cache/%s", sc_instance_path, EUCALYPTUS_ADMIN, file_id); /* cache is in admin's directory */ - snprintf (cached_path, BUFSIZE, "%s/%s", cached_dir, file_name); - snprintf (staging_path, BUFSIZE, "%s-staging", cached_path); - snprintf (digest_path, BUFSIZE, "%s-digest", cached_path); + snprintf (file_path, BUFSIZE, "%s/%s/%s/%s", sc_instance_path, user_id, instance_id, file_name); + snprintf (tmp_digest_path, BUFSIZE, "%s-digest", file_path); + snprintf (cached_dir, BUFSIZE, "%s/%s/cache/%s", sc_instance_path, EUCALYPTUS_ADMIN, file_id); /* cache is in admin's directory */ + snprintf (cached_path, BUFSIZE, "%s/%s", cached_dir, file_name); + snprintf (staging_path, BUFSIZE, "%s-staging", cached_path); + snprintf (digest_path, BUFSIZE, "%s-digest", cached_path); retry: /* under a lock, figure out the state of the file */ sem_p (sc_sem); /***** acquire lock *****/ - ensure_path_exists (cached_dir); /* creates missing directories */ + ensure_subdirectory_exists (file_path); /* creates missing directories */ struct stat mystat; int cached_exists = ! stat (cached_path, &mystat); int staging_exists = ! stat (staging_path, &mystat); + int e = ERROR; int action; enum { ABORT, VERIFY, WAIT, STAGE }; if ( staging_exists ) { @@ -466,34 +668,73 @@ static int get_cached_file (const char * user_id, const char * url, const char * } } - /* while still under lock... */ + /* while still under lock, decide whether to cache */ + long long file_size = 0; + int should_cache = 0; if (action==STAGE) { - if ( touch (staging_path) ) /* indicate that we'll be downloading it */ + e = walrus_object_by_url (url, tmp_digest_path); /* get the digest to see how big the file is */ + int digest_size = 0; + if (e==OK && stat (tmp_digest_path, &mystat)) { + digest_size = (int)mystat.st_size; + } + if (e==OK) { + /* pull the size out of the digest */ + char * xml_file = file2str (tmp_digest_path); + if (xml_file) { + file_size = str2longlong (xml_file, "", ""); + free (xml_file); + } + if (file_size > 0) { + if ( ok_to_cache (cached_path, file_size+digest_size) ) { /* will invalidate the cache, if needed */ + ensure_path_exists (cached_dir); /* creates missing directories */ + should_cache = 1; + if ( touch (staging_path) ) { /* indicate that we'll be caching it */ + logprintfl (EUCAERROR, "error: failed to create staging file %s\n", staging_path); + action = ABORT; + } + } + } else { + logprintfl (EUCAERROR, "error: failed to obtain file size from digest %s\n", url); + action = ABORT; + } + } else { + logprintfl (EUCAERROR, "error: failed to obtain digest from %s\n", url); action = ABORT; + } } sem_v (sc_sem); /***** release lock *****/ - int e = ERROR; switch (action) { case STAGE: - /* TODO: purge expired items from the cache */ - logprintfl (EUCAINFO, "bringing file %s into the cache...\n", cached_path); - e = walrus_image_by_manifest_url (url, cached_path); /* get the file */ - if (!e) e=walrus_object_by_url (url, digest_path); /* get the digest */ - + logprintfl (EUCAINFO, "downloding image into %s...\n", file_path); + e = walrus_image_by_manifest_url (url, file_path); + if ( e==OK && should_cache ) { + if ( (e=run ("cp", "-a", file_path, cached_path, 0)) != 0) { + logprintfl (EUCAERROR, "failed to copy file %s into cache at %s\n", file_path, cached_path); + } + if ( e==OK && (e=run ("cp", "-a", tmp_digest_path, digest_path, 0)) != 0) { + logprintfl (EUCAERROR, "failed to copy digest file %s into cache at %s\n", tmp_digest_path, digest_path); + } + } + sem_p (sc_sem); - unlink (staging_path); + if (should_cache) { + unlink (staging_path); + } if ( e ) { - logprintfl (EUCAERROR, "error: failed to download the file from Walrus\n"); - unlink (cached_path); - unlink (digest_path); - if ( rmdir (cached_dir) ) { - logprintfl (EUCAWARN, "warning: failed to remove cache directory %s\n", cached_dir); + logprintfl (EUCAERROR, "error: failed to download file from Walrus into %s\n", file_path); + unlink (file_path); + unlink (tmp_digest_path); + if (should_cache) { + unlink (cached_path); + unlink (digest_path); + if ( rmdir(cached_dir) ) { + logprintfl (EUCAWARN, "warning: failed to remove cache directory %s\n", cached_dir); + } } } sem_v (sc_sem); - if (e) return e; - /* yes, it is OK to fall through */ + break; case WAIT: logprintfl (EUCAINFO, "waiting for disapperance of %s...\n", staging_path); @@ -501,7 +742,7 @@ static int get_cached_file (const char * user_id, const char * url, const char * * download succeeded or it failed */ if ( (e=wait_for_file (NULL, staging_path, 180, "cached image")) ) return e; - /* yes, yes, it is OK to fall through */ + /* yes, it is OK to fall through */ case VERIFY: logprintfl (EUCAINFO, "verifying cached file in %s...\n", cached_path); @@ -521,6 +762,11 @@ static int get_cached_file (const char * user_id, const char * url, const char * } else { logprintfl (EUCAINFO, "due to failure, removed cache directory %s\n", cached_dir); } + } else { + /* touch the digest so cache can use mtime for invalidation */ + if ( touch (digest_path) ) { + logprintfl (EUCAERROR, "error: failed to touch digest file %s\n", digest_path); + } } sem_v (sc_sem); /***** release lock *****/ @@ -536,14 +782,14 @@ static int get_cached_file (const char * user_id, const char * url, const char * return ERROR; } else { /* all good - copy it, finally */ - ensure_subdirectory_exists (file_path); /* creates missing directories */ + ensure_subdirectory_exists (file_path); /* creates missing directories */ if ( (e=run ("cp", "-a", cached_path, file_path, 0)) != 0) { - logprintfl (EUCAERROR, "failed to copy cached file %s into run file %s\n", cached_path, file_path); - return e; + logprintfl (EUCAERROR, "failed to copy file %s from cache at %s\n", file_path, cached_path); + return ERROR; } } break; - + case ABORT: logprintfl (EUCAERROR, "get_cached_file() failed (errno=%d)\n", e); } diff --git a/storage/storage.h b/storage/storage.h index aefb228f0ef..f45ea664519 100644 --- a/storage/storage.h +++ b/storage/storage.h @@ -10,6 +10,7 @@ int scSetInstancePath(char *path); const char * scGetInstancePath(void); void scSaveInstanceInfo (const ncInstance * instance); ncInstance * scRecoverInstanceInfo (const char *instanceId); +void LogprintfCache (void); long long scFSCK (bunchOfInstances ** instances); int scGetConfigXML(char *user, char *amiId, char **out); int scMakeInstanceImage(char *user, char *imageId, char *imageURL, char *kernelId, char *kernelURL, char *ramdiskId, char *ramdiskURL, char *instId, char *keyName, char **instance_path, sem * s); @@ -18,5 +19,6 @@ int scStoreStringToInstanceFile (const char *userId, const char *instanceId, con /* utility function (exported for now so it can be tested by test.c) */ int ensure_path_exists (const char * path); +int test_cache (void); #endif diff --git a/util/eucalyptus.h b/util/eucalyptus.h index 85ddb4c6d07..88ad0b292ae 100644 --- a/util/eucalyptus.h +++ b/util/eucalyptus.h @@ -29,6 +29,7 @@ #define CONFIG_NC_SERVICE "NC_SERVICE" #define CONFIG_NC_PORT "NC_PORT" #define CONFIG_NODES "NODES" +#define CONFIG_NC_CACHE_SIZE "NC_CACHE_SIZE" /* name of the administrative user within Eucalyptus */ #define EUCALYPTUS_ADMIN "eucalyptus" @@ -39,7 +40,9 @@ #define MAXLOGFILESIZE 32768000 #define EUCA_MAX_GROUPS 64 #define EUCA_MAX_VOLUMES 3 +#define DEFAULT_NC_CACHE_SIZE 99999 /* in MB */ +#define MEGABYTE 1048576 #define OK 0 #define ERROR 1 diff --git a/util/misc.c b/util/misc.c index 954ad8466f5..c9803f7135b 100644 --- a/util/misc.c +++ b/util/misc.c @@ -12,6 +12,7 @@ #include /* powf */ #include #include /* open */ +#include /* utime */ #ifndef NO_AXIS /* for compiling on systems without Axis */ #include @@ -707,16 +708,20 @@ int logcat (int debug_level, const char * file_name) return got; } -/* create an empty file as a marker */ +/* "touch" a file, creating if necessary */ int touch (const char * path) { int ret = 0; int fd; - if ( (fd = open (path, O_EXCL | O_CREAT, 0644)) > 0 ) { + if ( (fd = open (path, O_WRONLY | O_CREAT | O_NONBLOCK, 0644)) >= 0 ) { close (fd); + if (utime (path, NULL)!=0) { + logprintfl (EUCAERROR, "error: touch(): failed to adjust time for %s (%s)\n", path, strerror (errno)); + ret = 1; + } } else { - logprintfl (EUCAERROR, "error: failed to create marker %s\n", path); + logprintfl (EUCAERROR, "error: touch(): failed to create/open file %s (%s)\n", path, strerror (errno)); ret = 1; } return ret; @@ -795,3 +800,84 @@ int dir_size (const char * path) closedir (dir); return size; } + +/* read file 'path' into a new string */ +char * file2str (const char * path) +{ + char * content = NULL; + struct stat mystat; + + if (stat (path, &mystat) < 0) { + logprintfl (EUCAERROR, "error: file2str() could not state file %s\n", path); + return content; + } + + if ( (content = malloc (mystat.st_size+BUFSIZE)) == NULL ) { + logprintfl (EUCAERROR, "error: file2str() out of memory reading file %s\n", path); + return content; + } + + int fp; + if ( ( fp = open (path, O_RDONLY) ) < 1 ) { + logprintfl (EUCAERROR, "error: file2str() failed to open file %s\n", path); + free (content); + content = NULL; + return content; + } + + int got; + char * p = content; + while ( ( got = read (fp, p, BUFSIZE) ) > 0 ) + p += got; + + if ( got < 0 ) { + logprintfl (EUCAERROR, "error: file2str() failed to read file %s\n", path); + free (content); + content = NULL; + return content; + } + + * p = '\0'; + return content; +} + +/* extract integer from str bound by 'begin' and 'end' */ +long long str2longlong (const char * str, const char * begin, const char * end) +{ + long long value = -1L; + + if ( str==NULL || begin==NULL || end==NULL || strlen (str)<3 || strlen (begin)<1 || strlen (end)<1 ) { + logprintfl (EUCAERROR, "error: str2int() called with bad parameters\n"); + return value; + } + + char * b = strstr ( str, begin ); + if ( b==NULL ) { + logprintfl (EUCAERROR, "error: str2int() beginning string '%s' not found\n", begin); + return value; + } + + char * e = strstr ( str, end ); + if ( e==NULL ) { + logprintfl (EUCAERROR, "error: str2int() end string '%s' not found\n", end); + return value; + } + + b += strlen (begin); // b now points at the supposed number + int len = e-b; + if ( len < 0 ) { + logprintfl (EUCAERROR, "error: str2int() there is nothing between '%s' and '%s'\n", begin, end); + return value; + } + + if ( len > BUFSIZE-1 ) { + logprintfl (EUCAERROR, "error: str2int() string between '%s' and '%s' is too long\n", begin, end); + return value; + } + + char buf [BUFSIZE]; + strncpy (buf, b, len); + value = atoll (buf); + + return value; +} diff --git a/util/misc.h b/util/misc.h index a75efadde73..62517d703a9 100644 --- a/util/misc.h +++ b/util/misc.h @@ -99,5 +99,7 @@ int logcat (int debug_level, const char * file_name); int touch (const char * path); int diff (const char * path1, const char * path2); int dir_size (const char * path); +char * file2str (const char * path); /* read file 'path' into a new string */ +long long str2longlong (const char * str, const char * begin, const char * end); /* extract integer from str bound by 'begin' and 'end' */ #endif