Liron Harel
Liron Harel

Reputation: 11247

Extract three numbers from a long number in code

I am building my own sharding solution with ASP.NET C# and MySQL. For the Id of each row I use the following:

So for example, an ID should be in the url like this:

http://mywebsite.com/folders/65535655354294967297

What I want to know is how to combine the numbers into a big number so I can extract the data later on. So for example, I won't use 1 as the shard ID, I would probably need to you 00001 because later it will be easier to extract that number by making a division on the whole number.

So how can I do that, what is the best way to build a long number with three seperate numerical values and then be able to extract them back in code?

I look for the most efficient way to do it in C#

Thanks.

Upvotes: 0

Views: 279

Answers (4)

L.B
L.B

Reputation: 116138

You can use hex represantations of numbers

ushort ShardId=1;
ushort TableTypeId = 100;
uint IncrementalNumber = 1000;

string url = ShardId.ToString("X4") + TableTypeId.ToString("X4")
                                    + IncrementalNumber.ToString("X8");

var i1 = Convert.ToUInt16(url.Substring(0, 4), 16);
var i2 = Convert.ToUInt16(url.Substring(4, 4), 16);
var i3 = Convert.ToUInt32(url.Substring(8, 8), 16);

OR

string url = (((ulong)ShardId << 48) | ((ulong)TableTypeId << 32) | IncrementalNumber)
             .ToString("X16");

var u  = Convert.ToUInt64(url,16);
var i1 = (ushort)(u >> 48);
var i2 = (ushort)((u >> 32) & 0xffff);
var i3 = (uint)(u & 0xffffffff);

Upvotes: 1

Lawrence Johnson
Lawrence Johnson

Reputation: 4043

You pretty much described the answer in your problem. Define a fixed width for each number.

int iShardId = 12; // Fixed width of 5
int iTableTypeId = 840; // Fixed width of 5
long lIncremental = 967295; // Fixed width of 10

string sMyId = String.Concat(iShardId.ToString("00000"), iTableTypeId.ToString("00000"), lIncremental.ToString("0000000000"));

You can then parse the string later (through an iHttpModule or whatever) using RegEx:

RegEx rMyText = new RegEx(@"/(?<shard>[0-9]{5})(?<table>[0-9]{5})(?<inc>[0-9]{10})/?$");
Match mMyValues = rMyText.Match(Request.Url.AbsolutePath);

if (mMyValues.Success) {
    int iShardId = Convert.ToInt32(mMyValues["shard"].Value);
    int iTableTypeId = Convert.ToInt32(mMyValues["table"].Value);
    long lIncremental = Convert.ToInt64(mMyValues["inc"].Value);
}
else {
    //The input didn't match
}

The RegEx is intended as a sample to parse the numbers, but obviously depending on how you plan to implement, you should adjust it to make sure that the input is limited to the values you are expecting by using beginning/terminating slashes or end of string ($).

Upvotes: 2

Dietz
Dietz

Reputation: 578

A solution could be to use binary numbers and append them together to form a single number.

  • Shard Id - Int (1-65535)
  • Table Type Id - Small Int (1-65535)
  • Incremental number (1 - 4294967295)

The Shard Id and the Table Id both requires 16 bit, and the Incremental number requires 16 bit. This means you can represent the data with 64 bits.

Example:

Shard Id

Dec: 7

Bin: 0000 0000 0000 0111

Table Type Id

Dec: 2435

Bin: 0000 1001 1000 0011

Incremental number

Dec: 23456457

Bin: 0001 0110 0101 1110 1010 1100 1001

Final number

Concat the binary values like

Shard id + table type id + incremental number

Bin: 0000 0000 0000 0111 0000 1001 1000 0011 0000 0001 0110 0101 1110 1010 1100 1001

Dec: 1980783105796809

Upvotes: 1

Rawling
Rawling

Reputation: 50114

Several options, roughly from longest (most readable?) to shortest (least readable)

  • Pad each number with zeroes to the longest it could be (00001000010000000001)
  • Separate the numbers with hyphens, or even slashes (1-1-1 or 1/1/1)
  • Combine your two ushorts and uint into a ulong and put that in the URL
  • Combine the eight bytes into an array, Base64 encode it and put that in the URL

I'd go with the second one - it's probably going to be shortest most of the time and is most human-readable.

Upvotes: 0

Related Questions