2 using System.Collections.Generic;
4 using System.Text.RegularExpressions;
19 private static readonly Regex DATE_REGEX =
new Regex(
"\\A(\\d{4})-(\\d{2})-(\\d{2})$");
24 private static readonly Regex DATETIME_REGEX =
new Regex(
"\\A(?<year>\\d{4})-(?<month>\\d{2})-(?<day>\\d{2})(?<time>\\s+(?<hour>\\d{1,2}):(?<min>\\d{2}):(?<sec>\\d{2})(?:\\.(?<ms>\\d{1,6}))?)?$");
30 private static readonly Regex IPV4_REGEX =
new Regex(
"\\A(?<a>\\d{1,3})\\.(?<b>\\d{1,3})\\.(?<c>\\d{1,3})\\.(?<d>\\d{1,3})$");
35 private static readonly Regex TIME_REGEX =
new Regex(
"\\A(?<hour>\\d{1,2}):(?<minute>\\d{2}):(?<seconds>\\d{2})(\\.(?<milliseconds>\\d{1,3}))?$");
45 private static readonly
int MIN_SUPPORTED_YEAR = 1000;
50 private static readonly
int MAX_SUPPORTED_YEAR = 2900;
55 private static readonly
int YEAR_1900 = 1900;
60 private static readonly TimeZoneInfo UTC = TimeZoneInfo.Utc;
62 private readonly
byte[] buffer;
63 private readonly
int buffer_size;
64 private int current_size;
65 private int hash_code;
66 private bool is_valid;
67 private long routingHash;
78 +
"Size given: " + size);
81 buffer =
new byte[size];
100 return this.hash_code;
111 private bool isBufferFull(
bool throw_if_full =
true)
113 if (this.current_size == this.buffer_size)
133 private bool willBufferOverflow(
int n,
bool throw_if_overflow =
true)
136 if ((this.current_size + n) > this.buffer_size)
138 if (throw_if_overflow)
139 throw new KineticaException($
"The buffer (of size {buffer_size}) does not have sufficient room in it to put {n} more byte(s) (current size is {this.current_size}).");
152 private void add(
byte b)
155 buffer.SetValue(b, current_size++);
167 this.willBufferOverflow(4);
181 byte[] int_bytes = BitConverter.GetBytes((
int)value);
184 foreach (
byte b
in int_bytes)
196 this.willBufferOverflow(1);
207 this.add((
byte)value);
218 this.willBufferOverflow(2);
230 byte[] short_bytes = BitConverter.GetBytes((
short)value);
233 foreach (
byte b
in short_bytes)
246 this.willBufferOverflow(8);
264 byte[] long_bytes = BitConverter.GetBytes((
long)value);
267 foreach (
byte b
in long_bytes)
279 this.willBufferOverflow(4);
285 this.add((
byte)0.0f);
286 this.add((
byte)0.0f);
287 this.add((
byte)0.0f);
288 this.add((
byte)0.0f);
293 byte[] float_bytes = BitConverter.GetBytes((
float)value);
296 foreach (
byte b
in float_bytes)
309 this.willBufferOverflow(8);
327 byte[] double_bytes = BitConverter.GetBytes((
double)value);
330 foreach (
byte b
in double_bytes)
352 System.Text.Encoding encoding =
new System.Text.UTF8Encoding();
353 byte[] input = encoding.GetBytes(value);
373 this.willBufferOverflow(N);
381 for (
int i = 0; i < N; ++i)
389 byte[] bytes = System.Text.Encoding.UTF8.GetBytes(value);
390 int byte_count = bytes.GetLength(0);
400 for (
int i = N; i > byte_count; --i)
406 for (
int i = (byte_count - 1); i >= 0; --i)
422 this.isBufferFull(
true);
432 Match match = DATE_REGEX.Match(value);
436 this.is_valid =
false;
442 int year, month, day;
444 System.Globalization.GregorianCalendar calendar =
new System.Globalization.GregorianCalendar();
449 year =
int.Parse(match.Groups[1].ToString());
450 month =
int.Parse(match.Groups[2].ToString());
451 day =
int.Parse(match.Groups[3].ToString());
452 date =
new DateTime(year, month, day, calendar);
458 this.is_valid =
false;
463 if ((year < MIN_SUPPORTED_YEAR) || (year > MAX_SUPPORTED_YEAR))
466 this.is_valid =
false;
470 int fixed_day_of_week = ((int)calendar.GetDayOfWeek(date) + 1);
473 int date_integer = (((year - YEAR_1900) << 21)
476 | (calendar.GetDayOfYear(date) << 3)
477 | fixed_day_of_week);
478 this.
addInt(date_integer);
491 this.isBufferFull(
true);
501 Match match = DATETIME_REGEX.Match(value);
505 this.is_valid =
false;
512 int year, month, day;
518 System.Globalization.GregorianCalendar calendar =
new System.Globalization.GregorianCalendar();
523 year =
int.Parse(match.Groups[
"year"].Value);
524 month =
int.Parse(match.Groups[
"month"].Value);
525 day =
int.Parse(match.Groups[
"day"].Value);
528 Group time_group = match.Groups[
"time"];
529 if (time_group.Success)
531 hour =
int.Parse(match.Groups[
"hour"].Value);
532 minute =
int.Parse(match.Groups[
"min"].Value);
533 second =
int.Parse(match.Groups[
"sec"].Value);
536 Group ms_group = match.Groups[
"ms"];
537 if (ms_group.Success)
539 msecond =
int.Parse(match.Groups[
"ms"].Value);
541 switch (ms_group.Value.Length)
544 msecond *= 100;
break;
546 msecond *= 10;
break;
549 msecond /= 10;
break;
551 msecond /= 100;
break;
553 msecond /= 1000;
break;
559 date =
new DateTime(year, month, day, hour, minute, second, msecond, calendar);
565 this.is_valid =
false;
570 if ((year < MIN_SUPPORTED_YEAR) || (year > MAX_SUPPORTED_YEAR))
573 this.is_valid =
false;
577 int fixed_day_of_week = ((int)calendar.GetDayOfWeek(date) + 1);
580 long datetime_long = (long)((((
long)(year - YEAR_1900)) << 53)
581 | (((
long)month) << 49)
582 | (((
long)day) << 44)
583 | (((
long)hour) << 39)
584 | (((
long)minute) << 33)
585 | (((
long)second) << 27)
586 | (((
long)msecond) << 17)
587 | (((
long)calendar.GetDayOfYear(date)) << 8)
588 | (((long)fixed_day_of_week) << 5));
601 public void addDecimal(
string value,
int precision,
int scale)
604 this.isBufferFull(
true);
607 int byteSize = (precision > 18) ? 12 : 8;
610 if (
string.IsNullOrEmpty(value) || value ==
"null")
612 for (
int i = 0; i < byteSize; i++)
620 if (!decimal.TryParse(value, System.Globalization.NumberStyles.Any,
621 System.Globalization.CultureInfo.InvariantCulture, out decimal parsedValue))
624 for (
int i = 0; i < byteSize; i++)
626 this.is_valid =
false;
631 decimal multiplier = (decimal)Math.Pow(10, scale);
634 decimal scaledValue = Math.Round(parsedValue * multiplier);
639 long longValue = (long)scaledValue;
645 this.willBufferOverflow(12);
648 BigInteger bigValue =
new BigInteger(scaledValue);
651 byte[] bigBytes = bigValue.ToByteArray();
652 byte[] result =
new byte[12];
655 int copyLen = Math.Min(bigBytes.Length, 12);
656 Array.Copy(bigBytes, result, copyLen);
659 if (bigValue < 0 && bigBytes.Length < 12)
661 for (
int i = bigBytes.Length; i < 12; i++)
666 foreach (
byte b
in result)
673 for (
int i = 0; i < byteSize; i++)
675 this.is_valid =
false;
689 this.isBufferFull(
true);
699 Match match = IPV4_REGEX.Match(value);
703 this.is_valid =
false;
714 a =
int.Parse(match.Groups[
"a"].Value);
715 b =
int.Parse(match.Groups[
"b"].Value);
716 c =
int.Parse(match.Groups[
"c"].Value);
717 d =
int.Parse(match.Groups[
"d"].Value);
723 this.is_valid =
false;
729 if ((a > 255) || (b > 255) || (c > 255) || (d > 255))
732 this.is_valid =
false;
737 int ipv4_integer = ((a << 24) | (b << 16) | (c << 8) | d);
738 this.
addInt(ipv4_integer);
752 this.isBufferFull(
true);
762 Match match = TIME_REGEX.Match(value);
766 this.is_valid =
false;
772 uint hour, minute, second, milliseconds;
777 hour = uint.Parse(match.Groups[
"hour"].Value);
778 minute = uint.Parse(match.Groups[
"minute"].Value);
779 second = uint.Parse(match.Groups[
"seconds"].Value);
780 Group msec_group = match.Groups[
"milliseconds"];
784 if (msec_group.Success)
786 milliseconds = uint.Parse(msec_group.Value);
789 switch (msec_group.Value.Length)
792 milliseconds *= 100;
break;
794 milliseconds *= 10;
break;
802 this.is_valid =
false;
807 if ((hour > 23) || (minute > 59) || (second > 59))
810 this.is_valid =
false;
815 int time_integer = (int)((hour << 26) | (minute << 20) | (second << 14) | (milliseconds << 4));
816 this.
addInt(time_integer);
834 DateTime time = EPOCH_DATE.AddMilliseconds((
double)value);
835 long fixed_day_of_week = ((long)time.DayOfWeek + 1);
837 long timestamp = (long)((((
long)(time.Year - YEAR_1900)) << 53)
838 | (((
long)(time.Month)) << 49)
839 | (((
long)time.Day) << 44)
840 | (((long)time.Hour) << 39)
841 | (((
long)time.Minute) << 33)
842 | (((long)time.Second) << 27)
843 | (((
long)time.Millisecond) << 17)
844 | (((long)time.DayOfYear) << 8)
845 | (fixed_day_of_week << 5));
860 if (this.current_size != this.buffer_size)
861 throw new KineticaException(
"The RecordKey buffer is not full; check that all the relevant values have been added.");
868 this.routingHash = murmur.val1;
869 this.hash_code = (int)(this.routingHash ^ ((this.routingHash >> 32) & 0x0000ffffL));
880 public int route(IList<int> routingTable)
885 return (routingTable[Math.Abs((
int)(
this.routingHash % routingTable.Count))] - 1);
void addCharN(string value, int N)
Appends a charN value to the buffer.
void addInt8(int? value)
Add an 8-bit integer to the buffer.
void addInt16(int? value)
Add a short (two bytes) to the buffer.
void addDecimal(string value, int precision, int scale)
Adds a decimal value to the buffer with specified precision and scale.
int route(IList< int > routingTable)
Given a routing table consisting of worker rank indices, choose a worker rank based on the hash of th...
void addDate(string value)
Adds a string to the buffer that has the 'date' property.
void addInt(int? value)
Add an integer to the buffer.
A binary key used for shard routing.
bool isValid()
Returns whether the key is valid or not.
RecordKey(int size)
Allocate the buffer for the record key with the given size.
void computeHashes()
Compute the hash of the key in the buffer.
void addTime(string value)
Adds a string to the buffer that has the 'time' property.
void addString(string value)
Add a string to the buffer.
void addIPv4(string value)
Adds a string to the buffer that has the 'ipv4' property.
void addTimeStamp(long? value)
Adds a long to the buffer that has the 'timestamp' property.
void addLong(long? value)
Add a long to the buffer.
void addDouble(double? value)
Add a double to the buffer.
void addDateTime(string value)
Adds a string to the buffer that has the 'datetime' property.
void addFloat(float? value)
Add a float to the buffer.
DateTime in YYYY-MM-DD HH:MM:SS.mmm format
static void murmurhash3_x64_128(byte[] key, uint offset, uint len, int seed, out LongPair output)
Returns the MurmurHash3_x64_128 hash, placing the result in output
int hashCode()
Returns key's hash code.