Tuesday, December 1, 2009

Getting a repeatable numerical representation of a string

I've working on some test code that would allows us to serve assets from fake asset hosts (ex. assets0.example.com) in which a virtual domain is used to point that host to a real server. This would allow us to increase the total number of requests a browser can make at a single time (most browsers are limited to 2 HTTP requests per host - a subdomain is considered a single host).  However, the problem is that we do not want to randomly change the assets host in which a file served from one request to the next.  For example, serving "/img/peter1.jpg" from asset0.example.com and then asset3.example.com the next time as this would cause the browser to re-download the image again just because the host changed.  This would be pointless and actually be more harmful to us in the end probably.

The question is how to compute which asset host to serve the file from without having to provide a whole ton of configuration.  The simple question is to convert the each character in the path to the desired asset to an ASCII numerical representation, add each character to a total number and then perform a modulus on the result.  Here is some example code (in this example we are assuming that there will be 4 assets hosts from asset0.example.com to asset3.example.com):


<cfset test = ArrayNew(1) />
<cfset test[1] = "/img/peter1.jpg" />
<cfset test[2] = "/img/peter2.jpg" />
<cfset test[3] = "/img/peter3.jpg" />
<cfset test[4] = "/img/peter4.jpg" />
<cfset test[5] = "/img/peter5.jpg" />
<cfset test[6] = "/img/matt1.jpg" />
<cfset test[7] = "/img/matt2.jpg" />
<cfset test[8] = "/img/matt3.jpg" />
<cfset test[9] = "/img/matt4.jpg" />
<cfset test[10] = "/img/matt5.jpg" />

<cffunction name="totalAsc" access="public" returntype="numeric" output="false">
<cfargument name="str" type="string" required="true">

<cfset var result = 0 />
<cfset var arr = arguments.str.toCharArray() />

<cfloop from="1" to="#ArrayLen(arr)#" index="i">
<cfset result = result + Asc(arr[i]) />
</cfloop>

<cfreturn result />
</cffunction>

<cfoutput>

<cfloop from="1" to="#arraylen(test)#" index="i">
<cfset value = test[i] />
<p>FILENAME: #test[i]# = TOTAL ASC VALUE: #totalAsc(value)# | MOD: #totalAsc(value) MOD 4#</p>
</cfloop>

</cfoutput>

Running this code results in this output:





FILENAME: /img/peter1.jpg = TOTAL ASC VALUE: 1371 | MOD: 3

FILENAME: /img/peter2.jpg = TOTAL ASC VALUE: 1372 | MOD: 0

FILENAME: /img/peter3.jpg = TOTAL ASC VALUE: 1373 | MOD: 1

FILENAME: /img/peter4.jpg = TOTAL ASC VALUE: 1374 | MOD: 2

FILENAME: /img/peter5.jpg = TOTAL ASC VALUE: 1375 | MOD: 3

FILENAME: /img/matt1.jpg = TOTAL ASC VALUE: 1265 | MOD: 1

FILENAME: /img/matt2.jpg = TOTAL ASC VALUE: 1266 | MOD: 2

FILENAME: /img/matt3.jpg = TOTAL ASC VALUE: 1267 | MOD: 3

FILENAME: /img/matt4.jpg = TOTAL ASC VALUE: 1268 | MOD: 0

FILENAME: /img/matt5.jpg = TOTAL ASC VALUE: 1269 | MOD: 1




As you can see, the modulus will always be the same for each asset path (unless the case of the asset path differs) and we can use the result of the modulus to always serve "/img/peter1.jpg" from asset3.example.com. No more randomness!  Pretty cool math trick, huh?

No comments:

Post a Comment