vcs-svn: implement perfect hash for node-prop keys
Instead of interning property names and comparing their string_pool keys, look them up in a table by string length, which should be about as fast. This is a small step towards removing dependence on string_pool. Signed-off-by: David Barr <david.barr@cordelta.com> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
This commit is contained in:
		
				
					committed by
					
						
						Jonathan Nieder
					
				
			
			
				
	
			
			
			
						parent
						
							c9d1c8ba05
						
					
				
				
					commit
					044ad2906a
				
			@ -14,6 +14,12 @@
 | 
				
			|||||||
#include "obj_pool.h"
 | 
					#include "obj_pool.h"
 | 
				
			||||||
#include "string_pool.h"
 | 
					#include "string_pool.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Compare start of string to literal of equal length;
 | 
				
			||||||
 | 
					 * must be guarded by length test.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					#define constcmp(s, ref) memcmp(s, ref, sizeof(ref) - 1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define NODEACT_REPLACE 4
 | 
					#define NODEACT_REPLACE 4
 | 
				
			||||||
#define NODEACT_DELETE 3
 | 
					#define NODEACT_DELETE 3
 | 
				
			||||||
#define NODEACT_ADD 2
 | 
					#define NODEACT_ADD 2
 | 
				
			||||||
@ -58,8 +64,7 @@ static struct {
 | 
				
			|||||||
} dump_ctx;
 | 
					} dump_ctx;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct {
 | 
					static struct {
 | 
				
			||||||
	uint32_t svn_log, svn_author, svn_date, svn_executable, svn_special, uuid,
 | 
						uint32_t uuid, revision_number, node_path, node_kind, node_action,
 | 
				
			||||||
		revision_number, node_path, node_kind, node_action,
 | 
					 | 
				
			||||||
		node_copyfrom_path, node_copyfrom_rev, text_content_length,
 | 
							node_copyfrom_path, node_copyfrom_rev, text_content_length,
 | 
				
			||||||
		prop_content_length, content_length, svn_fs_dump_format_version,
 | 
							prop_content_length, content_length, svn_fs_dump_format_version,
 | 
				
			||||||
		/* version 3 format */
 | 
							/* version 3 format */
 | 
				
			||||||
@ -96,11 +101,6 @@ static void reset_dump_ctx(uint32_t url)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void init_keys(void)
 | 
					static void init_keys(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	keys.svn_log = pool_intern("svn:log");
 | 
					 | 
				
			||||||
	keys.svn_author = pool_intern("svn:author");
 | 
					 | 
				
			||||||
	keys.svn_date = pool_intern("svn:date");
 | 
					 | 
				
			||||||
	keys.svn_executable = pool_intern("svn:executable");
 | 
					 | 
				
			||||||
	keys.svn_special = pool_intern("svn:special");
 | 
					 | 
				
			||||||
	keys.uuid = pool_intern("UUID");
 | 
						keys.uuid = pool_intern("UUID");
 | 
				
			||||||
	keys.revision_number = pool_intern("Revision-number");
 | 
						keys.revision_number = pool_intern("Revision-number");
 | 
				
			||||||
	keys.node_path = pool_intern("Node-path");
 | 
						keys.node_path = pool_intern("Node-path");
 | 
				
			||||||
@ -117,22 +117,43 @@ static void init_keys(void)
 | 
				
			|||||||
	keys.prop_delta = pool_intern("Prop-delta");
 | 
						keys.prop_delta = pool_intern("Prop-delta");
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_property(uint32_t key, const char *val, uint32_t len,
 | 
					static void handle_property(const struct strbuf *key_buf,
 | 
				
			||||||
 | 
									const char *val, uint32_t len,
 | 
				
			||||||
				uint32_t *type_set)
 | 
									uint32_t *type_set)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	if (key == keys.svn_log) {
 | 
						const char *key = key_buf->buf;
 | 
				
			||||||
 | 
						size_t keylen = key_buf->len;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (keylen + 1) {
 | 
				
			||||||
 | 
						case sizeof("svn:log"):
 | 
				
			||||||
 | 
							if (constcmp(key, "svn:log"))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		if (!val)
 | 
							if (!val)
 | 
				
			||||||
			die("invalid dump: unsets svn:log");
 | 
								die("invalid dump: unsets svn:log");
 | 
				
			||||||
		/* Value length excludes terminating nul. */
 | 
							/* Value length excludes terminating nul. */
 | 
				
			||||||
		rev_ctx.log = log_copy(len + 1, val);
 | 
							rev_ctx.log = log_copy(len + 1, val);
 | 
				
			||||||
	} else if (key == keys.svn_author) {
 | 
							break;
 | 
				
			||||||
 | 
						case sizeof("svn:author"):
 | 
				
			||||||
 | 
							if (constcmp(key, "svn:author"))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		rev_ctx.author = pool_intern(val);
 | 
							rev_ctx.author = pool_intern(val);
 | 
				
			||||||
	} else if (key == keys.svn_date) {
 | 
							break;
 | 
				
			||||||
 | 
						case sizeof("svn:date"):
 | 
				
			||||||
 | 
							if (constcmp(key, "svn:date"))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		if (!val)
 | 
							if (!val)
 | 
				
			||||||
			die("invalid dump: unsets svn:date");
 | 
								die("invalid dump: unsets svn:date");
 | 
				
			||||||
		if (parse_date_basic(val, &rev_ctx.timestamp, NULL))
 | 
							if (parse_date_basic(val, &rev_ctx.timestamp, NULL))
 | 
				
			||||||
			warning("invalid timestamp: %s", val);
 | 
								warning("invalid timestamp: %s", val);
 | 
				
			||||||
	} else if (key == keys.svn_executable || key == keys.svn_special) {
 | 
							break;
 | 
				
			||||||
 | 
						case sizeof("svn:executable"):
 | 
				
			||||||
 | 
						case sizeof("svn:special"):
 | 
				
			||||||
 | 
							if (keylen == strlen("svn:executable") &&
 | 
				
			||||||
 | 
							    constcmp(key, "svn:executable"))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							if (keylen == strlen("svn:special") &&
 | 
				
			||||||
 | 
							    constcmp(key, "svn:special"))
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
		if (*type_set) {
 | 
							if (*type_set) {
 | 
				
			||||||
			if (!val)
 | 
								if (!val)
 | 
				
			||||||
				return;
 | 
									return;
 | 
				
			||||||
@ -143,7 +164,7 @@ static void handle_property(uint32_t key, const char *val, uint32_t len,
 | 
				
			|||||||
			return;
 | 
								return;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		*type_set = 1;
 | 
							*type_set = 1;
 | 
				
			||||||
		node_ctx.type = key == keys.svn_executable ?
 | 
							node_ctx.type = keylen == strlen("svn:executable") ?
 | 
				
			||||||
				REPO_MODE_EXE :
 | 
									REPO_MODE_EXE :
 | 
				
			||||||
				REPO_MODE_LNK;
 | 
									REPO_MODE_LNK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
@ -158,7 +179,7 @@ static void die_short_read(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static void read_props(void)
 | 
					static void read_props(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uint32_t key = ~0;
 | 
						static struct strbuf key = STRBUF_INIT;
 | 
				
			||||||
	const char *t;
 | 
						const char *t;
 | 
				
			||||||
	/*
 | 
						/*
 | 
				
			||||||
	 * NEEDSWORK: to support simple mode changes like
 | 
						 * NEEDSWORK: to support simple mode changes like
 | 
				
			||||||
@ -195,16 +216,19 @@ static void read_props(void)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		switch (type) {
 | 
							switch (type) {
 | 
				
			||||||
		case 'K':
 | 
							case 'K':
 | 
				
			||||||
			key = pool_intern(val);
 | 
					 | 
				
			||||||
			continue;
 | 
					 | 
				
			||||||
		case 'D':
 | 
							case 'D':
 | 
				
			||||||
			key = pool_intern(val);
 | 
								strbuf_reset(&key);
 | 
				
			||||||
 | 
								if (val)
 | 
				
			||||||
 | 
									strbuf_add(&key, val, len);
 | 
				
			||||||
 | 
								if (type == 'K')
 | 
				
			||||||
 | 
									continue;
 | 
				
			||||||
 | 
								assert(type == 'D');
 | 
				
			||||||
			val = NULL;
 | 
								val = NULL;
 | 
				
			||||||
			len = 0;
 | 
								len = 0;
 | 
				
			||||||
			/* fall through */
 | 
								/* fall through */
 | 
				
			||||||
		case 'V':
 | 
							case 'V':
 | 
				
			||||||
			handle_property(key, val, len, &type_set);
 | 
								handle_property(&key, val, len, &type_set);
 | 
				
			||||||
			key = ~0;
 | 
								strbuf_reset(&key);
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		default:
 | 
							default:
 | 
				
			||||||
			die("invalid property line: %s\n", t);
 | 
								die("invalid property line: %s\n", t);
 | 
				
			||||||
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user