Skip to content

Commit

Permalink
Changes to mod_plate's sync behavior
Browse files Browse the repository at this point in the history
Added a apache flag, PlateUnknownResync, which controls whether a resync
happens when an unknown platefile_id is requested.

Added a config table entry, PlateAlias, which adds a name to platefile_id
mapping.
  • Loading branch information
novas0x2a committed Jun 10, 2010
1 parent 66c5d88 commit e0bb8e1
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 29 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -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
Expand Down
39 changes: 36 additions & 3 deletions src/vw/Plate/mod_plate.c
Expand Up @@ -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*/ \
Expand All @@ -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);\
Expand All @@ -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
Expand Down Expand Up @@ -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"),
Expand All @@ -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 }
};

Expand All @@ -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;
}

Expand Down
77 changes: 56 additions & 21 deletions src/vw/Plate/mod_plate_io.cc
Expand Up @@ -92,7 +92,51 @@ class PlateModule {

typedef std::map<int32, IndexCacheEntry> 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<int>(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<intptr_t>(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<Blob> get_blob(int platefile_id, const std::string& plate_filename, uint32 blob_id) const;
void sync_index_cache() const;

Expand Down Expand Up @@ -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))
Expand All @@ -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<int>(match[1]),
level = boost::lexical_cast<int>(match[2]),
const std::string& sid = match[1];

int level = boost::lexical_cast<int>(match[2]),
col = boost::lexical_cast<int>(match[3]),
row = boost::lexical_cast<int>(match[4]);
std::string format = boost::lexical_cast<std::string>(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 -----------------

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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<rule_entry*>(m_conf->rules->elts);
for (i = 0; i < m_conf->rules->nelts; ++i) {
rule_entry *entry = reinterpret_cast<rule_entry*>(&m_conf->rules->elts[i]);
rules.add_rule(entry->level, entry->name);
entry++;
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/vw/Plate/mod_plate_io.h
Expand Up @@ -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);
Expand Down
14 changes: 9 additions & 5 deletions src/vw/Plate/tests/Makefile.am
Expand Up @@ -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

Expand All @@ -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 =
Expand Down
64 changes: 64 additions & 0 deletions 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 <gtest/gtest.h>

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<intptr_t>::max(),
small = numeric_limits<intptr_t>::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<intptr_t>(apr_table_get(table, "zero")));
EXPECT_EQ(big, reinterpret_cast<intptr_t>(apr_table_get(table, "big")));
EXPECT_EQ(small, reinterpret_cast<intptr_t>(apr_table_get(table, "small")));

apr_pool_destroy(pool);
#endif
}

0 comments on commit e0bb8e1

Please sign in to comment.