diff --git a/.gitignore b/.gitignore index f65160204..69ae79174 100644 --- a/.gitignore +++ b/.gitignore @@ -183,6 +183,7 @@ Makefile.in /src/vw/Plate/tests/TestBlobManager /src/vw/Plate/tests/TestIndexPage /src/vw/Plate/tests/TestLocalIndex +/src/vw/Plate/tests/TestModPlate /src/vw/Plate/tests/TestPlateIndexServer /src/vw/Plate/tests/TestTileManipulation /src/vw/Plate/tiles2plate diff --git a/src/vw/Plate/mod_plate.c b/src/vw/Plate/mod_plate.c index d1f1bf4fc..0d1f872e7 100644 --- a/src/vw/Plate/mod_plate.c +++ b/src/vw/Plate/mod_plate.c @@ -69,6 +69,25 @@ static const char* handle_rule(cmd_parms* cmd, void* cfg, const char* raw_level, return NULL; } +static const char* handle_alias(cmd_parms* cmd, void* cfg, const char* name, const char* id) { + plate_config *conf = get_plate_config_mutable(cmd->server); + + // warning go away + (void)cfg; + + intptr_t id_i = atoi(id); + if (id_i == 0) + return "Illegal platefile id: 0"; + + // XXX: intptr_t guarantees that a pointer can be cast to it and back without + // changing it, but it doesn't guarantee that an intptr_t can be cast to a + // pointer and back without changing it. So this code is technically + // undefined. Sigh. + apr_table_setn(conf->alias, name, (const char*)id_i); + + return NULL; +} + #define ADD_STRING_CONFIG(key, check) \ static const char* handle_ ## key(cmd_parms* cmd, void* null, const char* arg) {\ /* warning go away*/ \ @@ -84,6 +103,8 @@ static const char* handle_rule(cmd_parms* cmd, void* cfg, const char* raw_level, #define ADD_INT_CONFIG(key, check) \ static const char* handle_ ## key(cmd_parms* cmd, void* null, const char* arg) {\ + /* warning go away*/ \ + (void)null; \ plate_config *cfg = get_plate_config_mutable(cmd->server);\ cfg->key = atoi(arg);\ const char *error = check(cfg->key);\ @@ -93,7 +114,15 @@ static const char* handle_rule(cmd_parms* cmd, void* cfg, const char* raw_level, return NULL;\ } - +#define ADD_FLAG_CONFIG(key)\ + static const char* handle_ ## key(cmd_parms* cmd, void* null, int on) {\ + /* warning go away*/ \ + (void)null; \ + plate_config *cfg = get_plate_config_mutable(cmd->server);\ + cfg->key = on ? 1 : 0;\ + ap_set_module_config(cmd->server->module_config, &plate_module, (void*)cfg);\ + return NULL;\ + } const char* is_ip_address(const char* arg) { // really stupid heuristic @@ -144,7 +173,7 @@ ADD_STRING_CONFIG(dem_id, is_platefile_id); ADD_STRING_CONFIG(servername, is_servername); ADD_INT_CONFIG(index_timeout, is_gt_zero); ADD_INT_CONFIG(index_tries, is_gt_zero); - +ADD_FLAG_CONFIG(unknown_resync); static const command_rec my_cmds[] = { AP_INIT_TAKE1("PlateRabbitMQIP", handle_rabbit_ip, NULL, RSRC_CONF, "The IP of the rabbitmq server"), @@ -154,6 +183,8 @@ static const command_rec my_cmds[] = { AP_INIT_TAKE12("PlateLogRule", handle_rule, NULL, RSRC_CONF, "A log rule to add to the vw::RuleSet"), AP_INIT_TAKE1("PlateIndexTimeout", handle_index_timeout, NULL, RSRC_CONF, "How long to wait for the index_server to respond"), AP_INIT_TAKE1("PlateIndexTries", handle_index_tries, NULL, RSRC_CONF, "How many times to try talking to the index_server"), + AP_INIT_TAKE2("PlateAlias", handle_alias, NULL, RSRC_CONF, "Name-to-platefile_id mappings"), + AP_INIT_FLAG("PlateUnknownResync", handle_unknown_resync, NULL, RSRC_CONF, "Should we resync the platefile list when someone asks for an unknown one?"), { NULL } }; @@ -168,7 +199,9 @@ static void* create_plate_config(apr_pool_t* p, server_rec* s) { conf->servername = NULL; conf->index_timeout = 3000; conf->index_tries = 3; - conf->rules = apr_array_make(p, 8, sizeof(rule_entry)); + conf->rules = apr_array_make(p, 2, sizeof(rule_entry)); + conf->alias = apr_table_make(p, 4); + conf->unknown_resync = 1; return conf; } diff --git a/src/vw/Plate/mod_plate_io.cc b/src/vw/Plate/mod_plate_io.cc index aa7af9631..e8e91a21b 100644 --- a/src/vw/Plate/mod_plate_io.cc +++ b/src/vw/Plate/mod_plate_io.cc @@ -92,7 +92,51 @@ class PlateModule { typedef std::map IndexCache; - const IndexCache& get_index() const { return index_cache; } + const IndexCache& get_index_cache() const { return index_cache; } + + const IndexCacheEntry& get_index(const std::string& id_str) const { + int id; + PlateModule::IndexCache::const_iterator index_i; + + try { + id = boost::lexical_cast(id_str); + } catch (const boost::bad_lexical_cast&) { + id = 0; + } + + // try it as an id (unless it's clearly wrong) + if (id != 0) { + index_i = index_cache.find(id); + if (index_i != index_cache.end()) + return index_i->second; + } + + // Try it as an alias + { + int id2 = reinterpret_cast(apr_table_get(m_conf->alias, id_str.c_str())); + if (id2) { + logger(VerboseDebugMessage) << "Alias " << id_str << " resolved to " << id2 << std::endl; + index_i = index_cache.find(id2); + if (index_i != index_cache.end()) { + return index_i->second; + } + } + } + + if (!m_conf->unknown_resync) + vw_throw(BadRequest() << "No such platefile [no resync] [id = " << id_str << "]"); + + // If we get an unknown platefile, resync just to make sure + logger(WarningMessage) << "Platefile [" << id_str << "] not in platefile cache. Resyncing." << std::endl; + sync_index_cache(); + + index_i = index_cache.find(id); + if (index_i == index_cache.end()) + vw_throw(BadRequest() << "No such platefile [after resync] [id = " << id_str << "]"); + + return index_i->second; + } + const boost::shared_ptr get_blob(int platefile_id, const std::string& plate_filename, uint32 blob_id) const; void sync_index_cache() const; @@ -219,7 +263,7 @@ struct raii { // --------------------------------------------------- int handle_image(request_rec *r, const std::string& url) { - static const boost::regex match_regex("/(\\d+)/(\\d+)/(\\d+)/(\\d+)\\.(\\w+)$"); + static const boost::regex match_regex("/(\\w+)/(\\d+)/(\\d+)/(\\d+)\\.(\\w+)$"); boost::smatch match; if (!boost::regex_search(url, match, match_regex)) @@ -234,31 +278,22 @@ int handle_image(request_rec *r, const std::string& url) { //logger(VerboseDebugMessage) << "Request Headers: " << std::endl; //apr_table_do(log_headers, 0, r->headers_in, NULL); - int id = boost::lexical_cast(match[1]), - level = boost::lexical_cast(match[2]), + const std::string& sid = match[1]; + + int level = boost::lexical_cast(match[2]), col = boost::lexical_cast(match[3]), row = boost::lexical_cast(match[4]); std::string format = boost::lexical_cast(match[5]); - mod_plate().logger(DebugMessage) << "Request Image: id[" << id + mod_plate().logger(DebugMessage) << "Request Image: id[" << sid << "] level[" << level << "] col[" << col << "] row[" << row << "] format[" << format << "]" << std::endl; - PlateModule::IndexCache::const_iterator index_i = mod_plate().get_index().find(id); + const PlateModule::IndexCacheEntry& index = mod_plate().get_index(sid); - if (index_i == mod_plate().get_index().end()) { - // If we get an unknown platefile, resync just to make sure - mod_plate().logger(WarningMessage) << "Platefile not in platefile cache. Resyncing." << std::endl; - mod_plate().sync_index_cache(); - - index_i = mod_plate().get_index().find(id); - if (index_i == mod_plate().get_index().end()) - vw_throw(BadRequest() << "No such platefile [id = " << id << "]"); - } - - const PlateModule::IndexCacheEntry& index = index_i->second; + int id = index.index->index_header().platefile_id(); // -------------- Access Plate Index ----------------- @@ -459,7 +494,7 @@ int handle_wtml(request_rec *r, const std::string& url) { query_to_map(query, r->args); bool show_all_layers = mapget(query, "all_layers", false); - BOOST_FOREACH( const id_cache& e, mod_plate().get_index() ) { + BOOST_FOREACH( const id_cache& e, mod_plate().get_index_cache() ) { const std::string filetype = e.second.index->index_header().tile_filetype(); // WWT can only handle jpg and png @@ -499,15 +534,15 @@ PlateModule::PlateModule(const server_rec *s) // Disable the config file vw::vw_settings().set_rc_filename(""); + int i; + LogRuleSet rules; if (m_conf->rules->nelts == 0) rules.add_rule(DebugMessage, "plate.apache"); else { - ssize_t i; - rule_entry *entry = reinterpret_cast(m_conf->rules->elts); for (i = 0; i < m_conf->rules->nelts; ++i) { + rule_entry *entry = reinterpret_cast(&m_conf->rules->elts[i]); rules.add_rule(entry->level, entry->name); - entry++; } } diff --git a/src/vw/Plate/mod_plate_io.h b/src/vw/Plate/mod_plate_io.h index 4a0a4de2a..31c308259 100644 --- a/src/vw/Plate/mod_plate_io.h +++ b/src/vw/Plate/mod_plate_io.h @@ -30,7 +30,9 @@ typedef struct { const char *servername; int index_timeout; int index_tries; + int unknown_resync; apr_array_header_t *rules; // This holds rule_entries + apr_table_t *alias; // key is name, value is id, an int stored as a const char* } plate_config; const plate_config* get_plate_config(const server_rec* s); diff --git a/src/vw/Plate/tests/Makefile.am b/src/vw/Plate/tests/Makefile.am index f5ab09079..5d466d8a8 100644 --- a/src/vw/Plate/tests/Makefile.am +++ b/src/vw/Plate/tests/Makefile.am @@ -17,10 +17,14 @@ TestIndexPage_SOURCES = TestIndexPage.cxx TestLocalIndex_SOURCES = TestLocalIndex.cxx TestAmqp_SOURCES = TestAmqp.cxx TestTileManipulation_SOURCES = TestTileManipulation.cxx -#TestPlateIndexServer_SOURCES = TestPlateIndexServer.cxx +TestModPlate_SOURCES = TestModPlate.cxx -TESTS = TestBlobManager TestBlobIO TestLocalIndex \ - TestIndexPage TestAmqp TestTileManipulation +TESTS = TestBlobManager TestBlobIO TestLocalIndex TestIndexPage TestAmqp \ + TestTileManipulation TestModPlate + +if MAKE_MODPLATE +MORE_FLAGS = -DVW_HAVE_APACHE=1 +endif #include $(top_srcdir)/config/instantiate.am @@ -30,8 +34,8 @@ endif # general ######################################################################## -AM_CPPFLAGS = @VW_CPPFLAGS@ -AM_LDFLAGS = @VW_LDFLAGS@ @PKG_IMAGE_LIBS@ @PKG_MATH_LIBS@ @PKG_CORE_LIBS@ @PKG_PLATE_LIBS@ +AM_CPPFLAGS = @VW_CPPFLAGS@ @APXS_CFLAGS@ $(MORE_FLAGS) +AM_LDFLAGS = @VW_LDFLAGS@ @APXS_LDFLAGS@ @PKG_IMAGE_LIBS@ @PKG_MATH_LIBS@ @PKG_CORE_LIBS@ @PKG_PLATE_LIBS@ check_PROGRAMS = $(TESTS) CLEANFILES = diff --git a/src/vw/Plate/tests/TestModPlate.cxx b/src/vw/Plate/tests/TestModPlate.cxx new file mode 100644 index 000000000..e3ce5e0c0 --- /dev/null +++ b/src/vw/Plate/tests/TestModPlate.cxx @@ -0,0 +1,64 @@ +// __BEGIN_LICENSE__ +// Copyright (C) 2006-2010 United States Government as represented by +// the Administrator of the National Aeronautics and Space Administration. +// All Rights Reserved. +// __END_LICENSE__ + +#include + +using namespace std; + +#if defined(VW_HAVE_APACHE) && (VW_HAVE_APACHE==1) +# define HAS_APACHE(x) x +#else +# define HAS_APACHE(x) DISABLED_ ## x +#endif + +TEST(ModPlate, HAS_APACHE(Assumptions)) { + // I'm storing an intptr_t in an apr_table, which expects a const char*. + // This test makes sure that's okay...ish + + ASSERT_GE(sizeof(intptr_t), sizeof(const char*)); + + volatile const char *buf1; + volatile intptr_t buf2; + + intptr_t zero = 0, + big = numeric_limits::max(), + small = numeric_limits::min(); + + buf1 = (const char*)zero; + buf2 = (intptr_t)buf1; + EXPECT_EQ(zero, buf2); + + buf1 = (const char*)big; + buf2 = (intptr_t)buf1; + EXPECT_EQ(big, buf2); + + buf1 = (const char*)small; + buf2 = (intptr_t)buf1; + EXPECT_EQ(small, buf2); + + // There doesn't seem to be any reliable way to LINK against apr/apache. Sigh. +#if 0 + apr_status_t ret; + apr_pool_t *pool; + apr_table_t *table; + + ret = apr_pool_create(&pool, NULL); + ASSERT_EQ(APR_SUCCESS, ret); + + apr_table_t *t = apr_table_make(pool, 4); + ASSERT_TRUE(t); + + apr_table_setn(table, "zero", (const char*)zero); + apr_table_setn(table, "big", (const char*)big); + apr_table_setn(table, "small", (const char*)small); + + EXPECT_EQ(zero, reinterpret_cast(apr_table_get(table, "zero"))); + EXPECT_EQ(big, reinterpret_cast(apr_table_get(table, "big"))); + EXPECT_EQ(small, reinterpret_cast(apr_table_get(table, "small"))); + + apr_pool_destroy(pool); +#endif +}