private void prepareHttpContext(StreamReader reader, HttpCtx ctx) { //var size = int.Parse(reader.ReadLine().Split(' ')[0]); ctx.Reset(); var line = reader.ReadLine(); // skip the 1st line do { line = reader.ReadLine(); if (ctx.Method == null) { ctx.ParseFirstLine(line); } else if (ctx.RequestBodyLength == 0) { line.FindIntegerAfter("content-length", out ctx.RequestBodyLength); } } while (!string.IsNullOrEmpty(line)); if (ctx.RequestBodyLength > 0) { Span <char> spanChar = stackalloc char[ctx.RequestBodyLength]; Span <byte> spanByte = ctx.Buffer.AsSpan() .Slice(ctx.RequestBodyStart, ctx.RequestBodyLength); reader.Read(spanChar); for (int i = 0; i < ctx.RequestBodyLength; i++) { spanByte[i] = (byte)spanChar[i]; } reader.ReadLine(); // empty line } }
public void ProcessWarmup() { var ctx = HttpCtx.Obtain(); warmer.GetOnce(ctx, warmId++); HttpCtx.Release(ctx); }
private void getSuggest(int queryId, HttpCtx ctx) { var query = ctx.Params; query.Add("query_id", queryId.ToString()); query.Add("limit", getRandom(1, 50)); double total = 4475.0; // country if (rnd.NextDouble() < 1683 / total) { query.Add("country", storage.Countries[getRandom(1, storage.Countries.Count)].Name); } // city if (rnd.NextDouble() < 1659 / total) { query.Add("city", storage.Cities[getRandom(1, storage.Cities.Count)].Name); } var queryStr = query.ToString(); var id = getRandom(1, Storage.MAX_ACCOUNTS); var statusCode = router.getSuggest.Process(ctx, id); if (statusCode != 200) { router.getSuggest.Process(ctx, id); // debug } }
public void GetOnce(HttpCtx ctx, int query_id) { if (storage.Cities.Count > 1) { ctx.Reset(); var r = rnd.NextDouble(); if (r < PROB_FILTER) { getFilter(query_id, ctx); } else if (r < PROB_GROUP) { getGroup(query_id, ctx); } else if (r < PROB_RECOMMEND) { getRecommend(query_id, ctx); } else { getSuggest(query_id, ctx); } } }
// synchronously process the request from requestBuffer, and return statusCode public int Process(HttpCtx ctx, int dummy) { var startTime = Stats.Watch.Elapsed; // path sanity check foreach (var query in ctx.Params) { var value = query.Value; if (value.IsEmpty) { return(400); } if (query.Key != "query_id") { // all other parameters are invalid return(400); } } // parse Json and process dto var buffer = ctx.Buffer; var start = ctx.RequestBodyStart; var dto = DtoLikes.Obtain(); int statusCode = 400; try { if (DtoLikes.Parse(buffer, start, dto, store)) { // update the likes in the storage statusCode = store.VerifyNewLikes(dto); if (statusCode == 202) { ctx.PostAction = () => { store.PostNewLikes(dto); DtoLikes.Release(dto); } } ; } } catch (Exception) { // fall through } if (ctx.PostAction == null) { DtoLikes.Release(dto); } var stopTime = Stats.Watch.Elapsed; ctx.ContextType = "PostLikes"; // return the result return(statusCode); }
public static HttpCtx Obtain() { if (!bag.TryTake(out var obj)) { obj = new HttpCtx(); } return(obj); }
/******************************** Helpers **********************************/ // sync! returns the reply length private int sendReply(HttpCtx ctx, int statusCode) { ctx.StatusCode = statusCode; switch (statusCode) { case 200: // 200 OK with optional body Array.Copy(Status200, 0, ctx.Buffer, ctx.ResponseStart + STATUS_POS, Status200.Length); AStringBuilder.ComposeInt(ctx.ResponseBodyLength, ctx.Buffer, ctx.ResponseStart + LENGTH_POS); break; case 201: case 202: // empty jsons if (statusCode == 201) { Array.Copy(Status201, 0, ctx.Buffer, ctx.ResponseStart + STATUS_POS, Status201.Length); } else { Array.Copy(Status202, 0, ctx.Buffer, ctx.ResponseStart + STATUS_POS, Status202.Length); } Array.Copy(emptyJsonLength, 0, ctx.Buffer, ctx.ResponseStart + LENGTH_POS, emptyJsonLength.Length); Array.Copy(emptyJson, 0, ctx.Buffer, ctx.ResponseBodyStart, emptyJson.Length); ctx.ResponseBodyLength = 2; break; case 211: // empty accounts ctx.StatusCode = 200; Array.Copy(Status200, 0, ctx.Buffer, ctx.ResponseStart + STATUS_POS, Status200.Length); Array.Copy(emptyAccountsLength, 0, ctx.Buffer, ctx.ResponseStart + LENGTH_POS, emptyAccountsLength.Length); Array.Copy(emptyAccounts, 0, ctx.Buffer, ctx.ResponseBodyStart, emptyAccounts.Length); ctx.ResponseBodyLength = emptyAccounts.Length; break; case 212: // empty groups ctx.StatusCode = 200; Array.Copy(Status200, 0, ctx.Buffer, ctx.ResponseStart + STATUS_POS, Status200.Length); Array.Copy(emptyGroupsLength, 0, ctx.Buffer, ctx.ResponseStart + LENGTH_POS, emptyGroupsLength.Length); Array.Copy(emptyGroups, 0, ctx.Buffer, ctx.ResponseBodyStart, emptyGroups.Length); ctx.ResponseBodyLength = emptyGroups.Length; break; case 400: // 400 bad request, empty body Array.Copy(Status400, 0, ctx.Buffer, ctx.ResponseStart + STATUS_POS, Status400.Length); Array.Copy(zeroLength, 0, ctx.Buffer, ctx.ResponseStart + LENGTH_POS, zeroLength.Length); ctx.ResponseBodyLength = 0; break; case 404: // 404 not found, empty body Array.Copy(Status404, 0, ctx.Buffer, ctx.ResponseStart + STATUS_POS, Status404.Length); Array.Copy(zeroLength, 0, ctx.Buffer, ctx.ResponseStart + LENGTH_POS, zeroLength.Length); ctx.ResponseBodyLength = 0; break; } var responseLength = responseHeaders.Length + ctx.ResponseBodyLength; //ctx.Complete(responseLength); return(responseLength); }
public void RunGet(TimeSpan warmupDeadline) { HttpCtx ctx = new HttpCtx(); int query_id = 0; while (Stats.Watch.Elapsed < warmupDeadline) { GetOnce(ctx, query_id++); } }
private void composeResponse(HttpCtx ctx, List <GroupItem> groupList, int limit) { // find and compose the response var sb = new AStringBuilder(ctx.Buffer, ctx.ResponseBodyStart); sb.Append("{\"groups\":["); bool firstGroup = true; foreach (var g in groupList) { if (firstGroup) { firstGroup = false; } else { sb.Append(','); } // count - always there sb.Append("{\"count\":").Append(g.Count); // sex if (g.sex > 0) { sb.Append(",\"sex\":\"").Append(g.ASex).Append('"'); } if (g.status > 0) { sb.Append(",\"status\":\"").Append(g.AStatus).Append('"'); } if (g.city > 0) { sb.Append(",\"city\":\"").Append(g.ACity).Append('"'); } if (g.country > 0) { sb.Append(",\"country\":\"").Append(g.ACountry).Append('"'); } if (g.interest > 0) { sb.Append(",\"interests\":\"").Append(g.AInterest).Append('"'); } sb.Append('}'); if (--limit == 0) { break; // enough } } sb.Append("]}"); ctx.ResponseBodyLength = sb.Count; }
// synchronously process the request, fill up responseBuffer, and return statusCode public int Process(HttpCtx ctx, int dummy) { // first step: check if the cache already has the calculated result for this set of parameters var cacheKey = ctx.Params.GetParamKey(); if (CachedResults.TryGetValue(cacheKey, out var cachedList)) { // bingo! already calculated before composeResponse(ctx, cachedList, ctx.Params.Limit); return(200); } var limit = 0; var order = 0; Keys keyMask = new Keys(); var keys = new List <Keys>(); var queryMask = new GroupQueryMask(); bool empty = false; ArraySegment <int> likers = null; int locationFrom = -1, locationTo = -1; int statusFrom = -1, statusTo = -1; int sexFrom = -1, sexTo = -1; int yearFrom = -1, yearTo = -1; int interestFrom = -1, interestTo = -1; foreach (var query in ctx.Params) { var value = query.Value; if (value.IsEmpty) { return(400); } if (query.Key == "query_id") { } // ignore else if (query.Key == "limit") { if (!value.TryToInt(out limit)) { return(400); } if (limit <= 0 || limit > 50) { return(400); } } else if (query.Key == "keys") { foreach (var key in value.Split(',')) { var bit = Keys.None; if (key == "sex") { bit = Keys.Sex; keys.Add(Keys.Sex); queryMask |= GroupQueryMask.KeySex; } else if (key == "status") { bit = Keys.Status; keys.Add(Keys.Status); queryMask |= GroupQueryMask.KeyStatus; } else if (key == "interests") { bit = Keys.Interests; keys.Add(Keys.Interests); queryMask |= GroupQueryMask.KeyInterest; } else if (key == "country") { bit = Keys.Country; keys.Add(Keys.Country); queryMask |= GroupQueryMask.KeyCountry; } else if (key == "city") { bit = Keys.City; keys.Add(Keys.City); queryMask |= GroupQueryMask.KeyCity; } if (bit == Keys.None) { return(400); } else { keyMask |= bit; } } if (keyMask == Keys.None) { return(400); } } else if (query.Key == "order") { if (!value.TryToInt(out order)) { return(400); } if (order != 1 && order != -1) { return(400); } } else if (query.Key == "sex") { if (value == "m") { sexFrom = sexTo = 1; } else if (value == "f") { sexFrom = sexTo = 2; } else { return(400); } queryMask |= GroupQueryMask.Sex; } else if (query.Key == "status") { if (value == DtoAccount.s_Free) { statusFrom = statusTo = 1; } else if (value == DtoAccount.s_Taken) { statusFrom = statusTo = 2; } else if (value == DtoAccount.s_Complicated) { statusFrom = statusTo = 3; } else { return(400); } queryMask |= GroupQueryMask.Status; } else if (query.Key == "country") { if (store.Countries.TryGetValue(value, out IRange countryInd)) { locationFrom = locationTo = countryInd.Index; } else { empty = true; } queryMask |= GroupQueryMask.Country; } else if (query.Key == "city") { if (store.Cities.TryGetValue(value, out IRange cityInd)) { locationFrom = locationTo = cityInd.Index; } else { empty = true; } queryMask |= GroupQueryMask.City; } else if (query.Key == "interests") { if (store.Interests.TryGetValue(value, out IRange interestRange)) { interestFrom = interestTo = interestRange.Index; } else { empty = true; } queryMask |= GroupQueryMask.Interests; } else if (query.Key == "likes") { if (!value.TryToInt(out int extId)) { return(400); } if (!Mapper.ExtIdToIntId(extId, out int id)) { return(404); } var acct = store.Accounts[id]; if (acct.LikedByIdx == 0 || acct.LikedByCount == 0) { empty = true; } else { likers = new ArraySegment <int>(store.LikedBy, acct.LikedByIdx, acct.LikedByCount); } queryMask |= GroupQueryMask.Likes; } else if (query.Key == "birth") { if (value.TryToInt(out int birthYear)) { if (store.BirthYears.TryGetValue(birthYear, out IRange yearMap)) { yearFrom = yearTo = yearMap.Index; } else { empty = true; } } else { return(400); } queryMask |= GroupQueryMask.Birth; } else if (query.Key == "joined") { if (value.TryToInt(out int joinYear)) { if (store.JoinYears.TryGetValue(joinYear, out IRange yearMap)) { yearFrom = yearTo = yearMap.Index; } else { empty = true; } } else { return(400); } queryMask |= GroupQueryMask.Joined; } else // all other parameters are invalid { return(400); } } if (limit == 0 || order == 0) { return(400); } if (empty) // shortcut, no groups will be found { return(212); // empty groups } // extend the from/to ranges based on the keys { if (keyMask.HasFlag(Keys.City) && locationFrom < 0) { locationFrom = 0; locationTo = store.Cities.Count; } if (keyMask.HasFlag(Keys.Country) && locationFrom < 0) { locationFrom = 0; locationTo = store.Countries.Count; } if (keyMask.HasFlag(Keys.Sex) && sexFrom < 0) { sexFrom = 1; sexTo = 2; } if (keyMask.HasFlag(Keys.Status) && statusFrom < 0) { statusFrom = 1; statusTo = 3; } if (keyMask.HasFlag(Keys.Interests) && interestFrom < 0) { interestFrom = 1; interestTo = store.Interests.Count - 1; } } // find the correct hypercube out of 4, or create new one for likes IHypercube cube = null; CubeKind cubeKind = CubeKind.None; if (keyMask.HasFlag(Keys.City) || queryMask.HasFlag(GroupQueryMask.City)) { if (queryMask.HasFlag(GroupQueryMask.Birth)) { if (queryMask.HasFlag(GroupQueryMask.Likes)) { cubeKind = CubeKind.CityBirth; } else { cube = store.CubeCityBirth; } } else { if (queryMask.HasFlag(GroupQueryMask.Likes)) { cubeKind = CubeKind.CityJoined; } else { cube = store.CubeCityJoined; } } } else { if (queryMask.HasFlag(GroupQueryMask.Birth)) { if (queryMask.HasFlag(GroupQueryMask.Likes)) { cubeKind = CubeKind.CountryBirth; } else { cube = store.CubeCountryBirth; } } else { if (queryMask.HasFlag(GroupQueryMask.Likes)) { cubeKind = CubeKind.CountryJoined; } else { cube = store.CubeCountryJoined; } } } HypercubeHash cubeHash = null; // for likes, create a custom hypercube and fill it up if (cube == null && likers != null) { if (!Pool <HypercubeHash> .TryGet(out cubeHash)) { cubeHash = new HypercubeHash(cubeKind, 20000); } else { cubeHash.Reset(cubeKind); } cube = cubeHash; foreach (var id in likers) { var acct = store.Accounts[id]; int statusIdx = (acct.Flags >> 1) & 3; int sexIdx = (acct.Flags & Account.Male) > 0 ? 1 : 2; int locationIdx = 0; int yearIdx = 0; switch (cubeKind) { case CubeKind.CityBirth: locationIdx = acct.CityIdx; yearIdx = acct.BirthIdx; break; case CubeKind.CityJoined: locationIdx = acct.CityIdx; yearIdx = acct.JoinedIdx; break; case CubeKind.CountryBirth: locationIdx = acct.CountryIdx; yearIdx = acct.BirthIdx; break; case CubeKind.CountryJoined: locationIdx = acct.CountryIdx; yearIdx = acct.JoinedIdx; break; default: throw new Exception("Unexpected CubeKind"); } cubeHash.Include(locationIdx, statusIdx, sexIdx, yearIdx, acct.InterestMask); } } else { cubeKind = cube.Kind; } // calculate the size of the group var size = (locationTo - locationFrom + 1) * (statusTo - statusFrom + 1) * (sexTo - sexFrom + 1) * (yearTo - yearFrom + 1) * (interestTo - interestFrom + 1); var groupList = new List <GroupItem>(size); cube.Slice( locationFrom, locationTo, statusFrom, statusTo, sexFrom, sexTo, yearFrom, yearTo, interestFrom, interestTo, visit); // local function, called by the cube void visit(int location, int status, int sex, int year, int interest, int count) { var gi = new GroupItem { store = store, Count = count }; if (keyMask.HasFlag(Keys.Interests)) { gi.interest = (byte)interest; } if (keyMask.HasFlag(Keys.Status)) { gi.status = (byte)status; } if (keyMask.HasFlag(Keys.Sex)) { gi.sex = (byte)sex; } if (keyMask.HasFlag(Keys.City)) { gi.city = (short)location; } if (keyMask.HasFlag(Keys.Country)) { gi.country = (byte)location; } groupList.Add(gi); } if (groupList.Count == 0) { if (cubeHash != null) { Pool <HypercubeHash> .Release(cubeHash); } CachedResults.TryAdd(cacheKey, groupList); return(212); } var groupComparer = new GroupComparer(order, keys); groupList.Sort(groupComparer); composeResponse(ctx, groupList, limit); // add to the cache for later reuse if (groupList.Count > 50) { groupList.RemoveRange(50, groupList.Count - 50); } CachedResults.TryAdd(cacheKey, groupList); // clean up if (cubeHash != null) { Pool <HypercubeHash> .Release(cubeHash); } ctx.ContextType = "GetGroup"; return(200); }
private void composeResults(HttpCtx ctx, List <int> ids, FilterQueryMask flags, int limit) { // find and compose the response var sb = new AStringBuilder(ctx.Buffer, ctx.ResponseBodyStart); sb.Append("{\"accounts\":["); bool firstEl = true; foreach (int id in ids) { var acct = store.Accounts[id]; if (firstEl) { firstEl = false; } else { sb.Append(','); } // id (always present) sb.Append("{\"id\":").Append(Mapper.IntIdToExtId(id)).Append(','); // sex if (flags.HasFlag(FilterQueryMask.Sex_eq)) { sb.Append(store.Male[id] ? "\"sex\":\"m\"," : "\"sex\":\"f\","); } // status if (flags.HasFlag(FilterQueryMask.Status_eq)) { sb.Append("\"status\":\""); if (store.Free[id]) { sb.Append(DtoAccount.s_Free); } else if (store.Taken[id]) { sb.Append(DtoAccount.s_Taken); } else { sb.Append(DtoAccount.s_Complicated); } sb.Append("\","); } // fname if (acct.FNameIdx > 0 && ( flags.HasFlag(FilterQueryMask.Fname_eq) || flags.HasFlag(FilterQueryMask.Fname_any) || flags.HasFlag(FilterQueryMask.Fname_null))) { sb.Append("\"fname\":\"").Append(store.Fnames[acct.FNameIdx].AName).Append("\","); } // sname if (acct.SNameIdx != 0 && ( flags.HasFlag(FilterQueryMask.Sname_eq) || flags.HasFlag(FilterQueryMask.Sname_starts) || flags.HasFlag(FilterQueryMask.Sname_null))) { sb.Append("\"sname\":\"").Append(store.Snames[acct.SNameIdx].AName).Append("\","); } // phone if (acct.Phone != null && ( flags.HasFlag(FilterQueryMask.Phone_code) || flags.HasFlag(FilterQueryMask.Phone_null))) { sb.Append("\"phone\":\"").Append(acct.Phone).Append("\","); } // country if (acct.CountryIdx > 0 && ( flags.HasFlag(FilterQueryMask.Country_eq) || flags.HasFlag(FilterQueryMask.Country_null))) { sb.Append("\"country\":\"").Append(store.Countries[acct.CountryIdx].AName).Append("\","); } // city if (acct.CityIdx > 0 && ( flags.HasFlag(FilterQueryMask.City_eq) || flags.HasFlag(FilterQueryMask.City_any) || flags.HasFlag(FilterQueryMask.City_null))) { sb.Append("\"city\":\"").Append(store.Cities[acct.CityIdx].AName).Append("\","); } // birth if (flags.HasFlag(FilterQueryMask.Birth_ltgt) || flags.HasFlag(FilterQueryMask.Birth_year)) { sb.Append("\"birth\":").Append(acct.Birth).Append(','); } // premium if (flags.HasFlag(FilterQueryMask.Premium_now) || flags.HasFlag(FilterQueryMask.Premium_null)) { if (acct.PStart != 0 || acct.PFinish != 0) { sb.Append("\"premium\":{\"start\":").Append(acct.PStart).Append(",\"finish\":").Append(acct.PFinish).Append("},"); } } // email sb.Append("\"email\":"); if (acct.Email == null) { sb.Append("null"); } else { sb.Append('"'); store.emailFromBuffer(acct.Email, sb); sb.Append('"'); } // interests and likes are not required sb.Append('}'); if (--limit <= 0) { break; } } sb.Append("]}"); ctx.ResponseBodyLength = sb.Count; }
// synchronously process the request, fill up responseBuffer, and return statusCode public int Process(HttpCtx ctx, int dummy) { var limit = 0; var finder = new Finder(store.All); HashSet <int> likers = null; var orGroup = 0; var flags = new FilterQueryMask(); foreach (var query in ctx.Params) { var value = query.Value; if (value.IsEmpty) { return(400); } if (query.Key == "query_id") { } // ignore else if (query.Key == "limit") { if (!value.TryToInt(out limit)) { return(400); } } else if (query.Key == "sex_eq") { if (value == "m") { finder.AndBitmap(store.Male); } else if (value == "f") { finder.AndBitmap(store.Female); } else { return(400); } flags |= FilterQueryMask.Sex_eq; } else if (query.Key == "email_domain") { if (store.Domains.TryGetValue(value, out var domainMap)) { finder.AndBitmap(domainMap as BitMap); } else { finder.AndBitmap(null); } flags |= FilterQueryMask.Email_domain; } else if (query.Key == "email_lt") { var ltHash = emailHash(value) + 1; finder.AddCondition(i => store.Accounts[i].GetEmailHash() < ltHash, 2); flags |= FilterQueryMask.Email_ltgt; } else if (query.Key == "email_gt") { var gtHash = emailHash(value); finder.AddCondition(i => store.Accounts[i].GetEmailHash() > gtHash, 2); flags |= FilterQueryMask.Email_ltgt; } else if (query.Key == "status_eq" || query.Key == "status_neq") { bool statusYes = query.Key == "status_eq"; BitMap statusMap; if (value == DtoAccount.s_Free) { statusMap = statusYes ? store.Free : store.NotFree; } else if (value == DtoAccount.s_Taken) { statusMap = statusYes ? store.Taken : store.NotTaken; } else if (value == DtoAccount.s_Complicated) { statusMap = statusYes ? store.Complicated : store.NotComplicated; } else { return(400); } finder.AndBitmap(statusMap); flags |= FilterQueryMask.Status_eq; } else if (query.Key == "fname_eq") { if (store.Fnames.TryGetValue(value, out IRange fnameMap)) { finder.AndBitmap(fnameMap as BitMap); } else { finder.AndBitmap(null); } flags |= FilterQueryMask.Fname_eq; } else if (query.Key == "fname_any") { var fnames = value.Split(','); foreach (var s in fnames) { if (store.Fnames.TryGetValue(s, out IRange fnameOneMap)) { finder.OrBitmap(orGroup, fnameOneMap as BitMap); } } if (fnames.Length > 0) { orGroup++; } else { finder.AndBitmap(null); } flags |= FilterQueryMask.Fname_any; } else if (query.Key == "fname_null") { if (value == "0") { finder.AndBitmap(store.FnameYes); } else if (value == "1") { finder.AndBitmap(store.FnameNo); } else { return(400); } flags |= FilterQueryMask.Fname_null; } else if (query.Key == "sname_eq") { if (store.Snames2.TryGetValue(value[0] + (value[1] << 16), out var snameInd)) { finder.AndBitmap(snameInd as BitMap); } else { finder.AndBitmap(null); } finder.AddCondition(i => store.Snames[store.Accounts[i].SNameIdx].Name == value, 2); flags |= FilterQueryMask.Sname_eq; } else if (query.Key == "sname_starts") { int snameKey = value[0] + (value[1] << 8); if (value.Length > 2) { snameKey += (value[2] << 16) + (value[3] << 24); } if (store.Snames2.TryGetValue(snameKey, out var snameInd)) { finder.AndBitmap(snameInd as BitMap); } else { finder.AndBitmap(null); } finder.AddCondition(i => { return(store.Accounts[i].SNameIdx > 0 && store.Snames[store.Accounts[i].SNameIdx].AName.StartsWith(value)); }, 2); flags |= FilterQueryMask.Sname_starts; } else if (query.Key == "sname_null") { if (value == "0") { finder.AndBitmap(store.SnameYes); } else if (value == "1") { finder.AndBitmap(store.SnameNo); } else { return(400); } flags |= FilterQueryMask.Sname_null; } else if (query.Key == "phone_code") { if (store.AreaCodes.TryGetValue(value, out IRange areaInd)) { finder.AndBitmap(areaInd as BitMap); } else { finder.AndBitmap(null); } flags |= FilterQueryMask.Phone_code; } else if (query.Key == "phone_null") { if (value == "0") { finder.AndBitmap(store.PhoneYes); } else if (value == "1") { finder.AndBitmap(store.PhoneNo); } else { return(400); } flags |= FilterQueryMask.Phone_null; } else if (query.Key == "country_eq") { if (store.Countries.TryGetValue(value, out IRange countryInd)) { finder.AndBitmap(countryInd as BitMap); } else { finder.AndBitmap(null); } flags |= FilterQueryMask.Country_eq; } else if (query.Key == "country_null") { if (value == "0") { finder.AndBitmap(store.CountryYes); } else if (value == "1") { finder.AndBitmap(store.CountryNo); } else { return(400); } flags |= FilterQueryMask.Country_null; } else if (query.Key == "city_eq") { if (store.Cities.TryGetValue(value, out var cityBm)) { finder.AndBitmap(cityBm as BitMap); } else { finder.AndBitmap(null); } flags |= FilterQueryMask.City_eq; } else if (query.Key == "city_any") { var cities = value.Split(','); foreach (var s in cities) { if (store.Cities.TryGetValue(s, out var cityInd)) { finder.OrBitmap(orGroup, cityInd as BitMap); } } if (cities.Length > 0) { orGroup++; } else { finder.AndBitmap(null); } flags |= FilterQueryMask.City_any; } else if (query.Key == "city_null") { if (value == "0") { finder.AndBitmap(store.CityYes); } else if (value == "1") { finder.AndBitmap(store.CityNo); } else { return(400); } flags |= FilterQueryMask.City_null; } else if (query.Key == "birth_lt") { if (value.TryToInt(out int birthDay)) { finder.AddCondition(i => store.Accounts[i].Birth < birthDay, 1); } else { return(400); } flags |= FilterQueryMask.Birth_ltgt; } else if (query.Key == "birth_gt") { if (value.TryToInt(out int birthDay)) { finder.AddCondition(i => store.Accounts[i].Birth > birthDay, 1); } else { return(400); } flags |= FilterQueryMask.Birth_ltgt; } else if (query.Key == "birth_year") { if (value.TryToInt(out int birthYear)) { if (store.BirthYears.TryGetValue(birthYear, out IRange yearMap)) { finder.AndBitmap(yearMap as BitMap); } else { finder.AndBitmap(null); } } else { return(400); } flags |= FilterQueryMask.Birth_year; } else if (query.Key == "interests_contains") { foreach (var s in value.Split(',')) { if (store.Interests.TryGetValue(s, out IRange interestRange)) { finder.AndBitmap(interestRange as BitMap); } } flags |= FilterQueryMask.Interests_all; } else if (query.Key == "interests_any") { var parts = value.Split(','); foreach (var s in parts) { if (store.Interests.TryGetValue(s, out IRange interestRange)) { finder.OrBitmap(orGroup, interestRange as BitMap); } } if (parts.Length > 0) { orGroup++; } flags |= FilterQueryMask.Interests_any; } else if (query.Key == "likes_contains") { foreach (var s in value.Split(',')) { if (!s.TryToInt(out int extId)) { return(400); } if (!Mapper.ExtIdToIntId(extId, out int id)) { finder.AndBitmap(null); break; } var acct = store.Accounts[id]; if (acct.LikedByCount == 0) { finder.AndBitmap(null); break; } var likedBy = new ArraySegment <int>(store.LikedBy, acct.LikedByIdx, acct.LikedByCount); if (likers == null) { likers = new HashSet <int>(likedBy); } else { likers.IntersectWith(likedBy); } } if (likers == null || likers.Count == 0) { finder.AndBitmap(null); } flags |= FilterQueryMask.Likes_contains; } else if (query.Key == "premium_now") { finder.AndBitmap(store.PremiumNow); flags |= FilterQueryMask.Premium_now; } else if (query.Key == "premium_null") { if (value == "0") { finder.AndBitmap(store.PremiumYes); } else if (value == "1") { finder.AndBitmap(store.PremiumNo); } else { return(400); } flags |= FilterQueryMask.Premium_null; } else // all other parameters are invalid { return(400); } } if (limit <= 0) { return(400); } // shortcut if (!finder.Prepare()) { return(211); } // check in the cache first var cacheKey = ctx.Params.GetParamKey(); if (CachedResults.TryGetValue(cacheKey, out var cachedList)) { if (cachedList.Count >= limit) { // bingo! compose the cached list composeResults(ctx, cachedList, flags, limit); return(200); } } var result = new List <int>(); if (likers == null) { // all bitmaps and conditions are handled by finder finder.Find(limit, id => { result.Add(id); return(true); }); } else { // create the list for filtered ids foreach (var id in likers) { if (finder.Check(id)) { result.Add(id); } } // sort in the descending order and result.Sort((x, y) => y.CompareTo(x)); if (result.Count > 50) { result.RemoveRange(50, result.Count - 50); } } // serialize into the output buffer composeResults(ctx, result, flags, limit); // store in cache if (!CachedResults.TryAdd(cacheKey, result)) { if (CachedResults.TryGetValue(cacheKey, out var oldCache) && oldCache.Count < result.Count) { CachedResults[cacheKey] = result; // this entry has bigger size, replace the old cache } } ctx.ContextType = "GetFilter"; return(200); }
// synchronously process the request, fill up responseBuffer, and return statusCode public int Process(HttpCtx ctx, int id) { var limit = 0; if (!Mapper.ExtIdToIntId(id, out id)) { return(404); // no mapping exists } var finder = new Finder(store.All); finder.AndBitmap(store.PremiumFreeMale); // placeholder, to be replaced for each category var flags = new RecommendQueryMask(); var startTime = Stats.Watch.Elapsed; foreach (var query in ctx.Params) { var value = query.Value; if (value.IsEmpty) { return(400); } if (query.Key == "query_id") { } // ignore else if (query.Key == "limit") { if (!value.TryToInt(out limit)) { return(400); } } else if (query.Key == "country") { if (value.IsEmpty) { return(400); } if (store.Countries.TryGetValue(value, out IRange countryInd)) { finder.AndBitmap(countryInd as BitMap); } else { finder.AndBitmap(null); } flags |= RecommendQueryMask.Country; } else if (query.Key == "city") { if (value.IsEmpty) { return(400); } if (store.Cities.TryGetValue(value, out var cityBm)) { finder.AndBitmap(cityBm as BitMap); } else { finder.AndBitmap(null); } flags |= RecommendQueryMask.City; } else // all other parameters are invalid { return(400); } } if (limit <= 0) { return(400); } var acct = store.Accounts[id]; if (acct.IsEmpty()) { return(404); // no such user } if (acct.InterestMask.Count == 0) { return(211); // no interests => zero compatibility } if (finder.DefaultBitmap == null || acct.InterestMask.Count == 0) // shortcut { return(211); // empty accounts } #if false finder.AddCondition(i => acct.InterestMask.Any(store.Accounts[i].InterestMask), 0); #else for (int i = 1; i < BitMap96.MAX_BITS; i++) { if (acct.InterestMask.IsSet(i)) { finder.OrBitmap(0, store.Interests[i] as BitMap); } } #endif var findContext = new FindContext(store, finder, acct, limit); for (int category = 1; category <= 6; category++) { if (findContext.Select(category) >= limit) { break; } } // compose the response var sb = new AStringBuilder(ctx.Buffer, ctx.ResponseBodyStart); sb.Append("{\"accounts\":["); bool firstEl = true; // pick first limit users from selected foreach (var kv in findContext.Selected) { var i = kv.Value; var a = store.Accounts[i]; if (firstEl) { firstEl = false; } else { sb.Append(','); } // id (always present) sb.Append("{\"id\":").Append(Mapper.IntIdToExtId(i)).Append(','); // email sb.Append("\"email\":"); if (a.Email == null) { sb.Append("null"); } else { sb.Append('"'); store.emailFromBuffer(a.Email, sb); sb.Append("\","); } // status sb.Append("\"status\":\""); if (a.IsFree()) { sb.Append(DtoAccount.s_Free); } else if (a.IsTaken()) { sb.Append(DtoAccount.s_Taken); } else { sb.Append(DtoAccount.s_Complicated); } sb.Append("\","); // fname if (a.FNameIdx > 0) { sb.Append("\"fname\":\"").Append(store.Fnames[a.FNameIdx].AName).Append("\","); } // sname if (a.SNameIdx > 0) { sb.Append("\"sname\":\"").Append(store.Snames[a.SNameIdx].AName).Append("\","); } // premium if (store.PremiumYes[i]) { sb.Append("\"premium\":{\"start\":").Append(a.PStart).Append(",\"finish\":").Append(a.PFinish).Append("},"); } // birth sb.Append("\"birth\":").Append(a.Birth).Append('}'); } ; // finalize the output sb.Append("]}"); ctx.ResponseBodyLength = sb.Count; var stopTime = Stats.Watch.Elapsed; ctx.ContextType = "GetRecommend"; return(200); }
private void getFilter(int queryId, HttpCtx ctx) { var query = ctx.Params; query.Add("query_id", queryId.ToString()); query.Add("limit", getRandom(1, 50)); double total = 51197.0; int maxOr = 0; // sex if (rnd.NextDouble() < 13309 / total) { query.Add("sex_eq", getRandom(new[] { Storage.s_Male, Storage.s_Female })); } // status if (rnd.NextDouble() < 6613 / total) { query.Add("status_eq", getRandom(new[] { Storage.s_Free, Storage.s_Taken, Storage.s_Complicated })); } // country if (rnd.NextDouble() < 3689 / total) { query.Add("country_eq", storage.Countries[getRandom(1, storage.Countries.Count)].Name); } else if (rnd.NextDouble() < 3560 / total) { query.Add("country_null", getRandom(0, 2)); } // interests if (rnd.NextDouble() < 3000 / total) { for (int i = 1; i <= 3; i++) { query.Add("interests_contains", storage.Interests[getRandom(1, storage.Interests.Count)].Name); } } else if (rnd.NextDouble() < 2969 / total && maxOr < 2) { for (int i = 1; i <= 6; i++) { query.Add("interests_any", storage.Interests[getRandom(1, storage.Interests.Count)].Name); } maxOr++; } // birth if (rnd.NextDouble() < 2890 / total) { query.Add(getRandom(new[] { "birth_lt", "birth_gt" }), getRandom(new DateTime(1950, 1, 1).ToUnix(), Storage.MinPremium.ToUnix())); } else if (rnd.NextDouble() < 1420 / total) { query.Add("birth_year", storage.BirthYears[getRandom(1, storage.BirthYears.Count)].Name); } // likes_contains if (rnd.NextDouble() < 2137 / total) { for (int i = 1; i <= 4; i++) { query.Add("likes_contains", getRandom(1, Storage.MAX_ACCOUNTS)); } } // email if (rnd.NextDouble() < 1934 / total) { query.Add(getRandom(new[] { "email_lt", "email_gt" }), (char)getRandom(97, 97 + 26) + (char)getRandom(97, 97 + 26)); } else if (rnd.NextDouble() < 924 / total) { query.Add("email_domain", storage.Domains[getRandom(1, storage.Domains.Count)].Name); } // city if (rnd.NextDouble() < 1541 / total) { query.Add("city_eq", storage.Cities[getRandom(1, storage.Cities.Count)].Name); } else if (rnd.NextDouble() < 1475 / total && maxOr < 2) { for (int i = 1; i <= 6; i++) { query.Add("city_any", storage.Cities[getRandom(1, storage.Cities.Count)].Name); } maxOr++; } else if (rnd.NextDouble() < 1468 / total) { query.Add("city_null", getRandom(0, 2)); } // premium if (rnd.NextDouble() < 1113 / total) { query.Add("premium_now", getRandom(0, 2)); } // sname if (rnd.NextDouble() < 511 / total) { query.Add("sname_starts", "ab"); } else if (rnd.NextDouble() < 505 / total) { query.Add("sname_null", getRandom(0, 2)); } // fname if (rnd.NextDouble() < 498 / total) { query.Add("fname_null", getRandom(0, 2)); } else if (rnd.NextDouble() < 482 / total && maxOr < 2) { for (int i = 1; i <= 6; i++) { query.Add("fname_any", storage.Fnames[getRandom(1, storage.Fnames.Count)].Name); } maxOr++; } // phone if (rnd.NextDouble() < 397 / total) { query.Add("phone_null", getRandom(0, 2)); } else if (rnd.NextDouble() < 365 / total) { query.Add("phone_code", storage.AreaCodes[getRandom(1, storage.AreaCodes.Count)].Name); } var queryStr = query.ToString(); var statusCode = router.getFilter.Process(ctx, 0); if (statusCode != 200) { router.getFilter.Process(ctx, 0); // debug } }
// synchronously process the request from requestBuffer, and return statusCode public int Process(HttpCtx ctx, int extId) { var startTime = Stats.Watch.Elapsed; // query sanity check foreach (var query in ctx.Params) { var value = query.Value; if (value.IsEmpty) { return(400); } if (query.Key != "query_id") { // all other parameters are invalid return(400); } } // translate to internal id and check for account existance if (!Mapper.ExtIdToIntId(extId, out int id) || !store.All[id]) { return(404); } // parse Json var dto = DtoAccount.Obtain(); dto.id = id; int statusCode = 400; try { JsonReader reader = new JsonReader(ctx.Buffer, ctx.RequestBodyStart); if (DtoAccount.Parse(ref reader, dto, store) && dto.flags != 0) { // update the account, register post-process action statusCode = store.ValidateUpdateAccount(dto); if (statusCode == 202) { ctx.PostAction = () => { store.PostUpdateAccount(dto); DtoAccount.Release(dto); } } ; } } catch (Exception) { // fall through } // return the borrowed object if (ctx.PostAction == null) { DtoAccount.Release(dto); } var stopTime = Stats.Watch.Elapsed; ctx.ContextType = "PostUpdate"; return(statusCode); }
public TimeSpan TestPhase(int phase, string path, bool verify) { Log.Info("Testing phase " + phase); TimeSpan totalPhaseTime = new TimeSpan(); var getPost = phase == 2 ? "post" : "get"; var ammoFileName = path + "/ammo/phase_" + phase + "_" + getPost + ".ammo"; var answersFileName = path + "/answers/phase_" + phase + "_" + getPost + ".answ"; var postActions = new List <Action>(); var ctx = new HttpCtx(); using (var reqFs = new FileStream(ammoFileName, FileMode.Open, FileAccess.Read)) using (var reqStream = new StreamReader(reqFs, Encoding.UTF8)) using (var ansFs = new FileStream(answersFileName, FileMode.Open, FileAccess.Read)) using (var ansStream = new StreamReader(ansFs, Encoding.ASCII, false)) { while (!reqStream.EndOfStream) { prepareHttpContext(reqStream, ctx); var startTime = Stats.Watch.Elapsed; router.ProcessRequest(ctx); // actual request processing if (ctx.PostAction != null) { postActions.Add(ctx.PostAction); ctx.PostAction = null; } var elapsed = Stats.Watch.Elapsed - startTime; Stats.ReportContextTime(ctx.ContextType, elapsed); totalPhaseTime += elapsed; if (verify) { var ans = ansStream.ReadLine().Split('\t'); var expStatus = int.Parse(ans[2]); var strAnsw = ""; // Encoding.ASCII.GetString(ctx.Buffer, ctx.ResponseStart, ctx.ResponseBodyStart- ctx.ResponseStart); if (ans.Length > 3) { strAnsw = ans[3]; } //var qPath = ctx.Request.Path.ToString(); if (ctx.StatusCode != expStatus) { Console.WriteLine("\n{0} {1}", ans[0], Uri.UnescapeDataString(ans[1])); Console.WriteLine("Received statusCode {0} instead of {1}", ctx.StatusCode, expStatus); router.ProcessRequest(ctx); } else if (strAnsw.Length == 0 && ctx.ResponseBodyLength == 0) { // both null, everything is OK } else { // compare jsons object jsResp = null; object jsAnsw = null; try { jsResp = JsonSerializer.Deserialize <dynamic>(ctx.Buffer, ctx.ResponseBodyStart); jsAnsw = JsonSerializer.Deserialize <dynamic>(strAnsw); } catch (Exception e) { Console.WriteLine(e.Message); break; } if (!compareDynamic(jsAnsw, jsResp)) { //compareDynamic(jsAnsw, jsResp); Console.WriteLine("\n{0} {1}", ans[0], Uri.UnescapeDataString(ans[1])); Console.WriteLine("\tReceived\n{0}\n\tInstead of\n{1}", Encoding.UTF8.GetString(ctx.Buffer, ctx.ResponseBodyStart, ctx.ResponseBodyLength), Encoding.UTF8.GetString(JsonSerializer.Serialize <dynamic>(jsAnsw)) ); //Console.ReadLine(); router.ProcessRequest(ctx); } } } ctx.Reset(); } } // process post-actions if (verify) // if not verifying, likely testing for performance { foreach (var a in postActions) { a.Invoke(); } } postActions.Clear(); return(totalPhaseTime); }
public static void Release(HttpCtx bb) { bb.Reset(); bag.Add(bb); }
private void getGroup(int queryId, HttpCtx ctx) { var query = ctx.Params; query.Add("query_id", queryId.ToString()); query.Add("limit", getRandom(1, 50)); double total = 19729.0; bool countryUsed = false; bool cityUsed = false; bool birthUsed = false; // key status if (rnd.NextDouble() < 2618 / total) { query.Add("keys", "status"); } // key status if (rnd.NextDouble() < 1895 / total) { query.Add("keys", "sex"); } // key country if (rnd.NextDouble() < 1922 / total) { query.Add("keys", "country"); countryUsed = true; } else // key city if (rnd.NextDouble() < 1871 / total && !countryUsed) { query.Add("keys", "city"); cityUsed = true; } // key interests if (rnd.NextDouble() < 1116 / total && !countryUsed) { query.Add("keys", "interests"); } // birth if (rnd.NextDouble() < 2496 / total) { query.Add("birth", storage.BirthYears[getRandom(1, storage.BirthYears.Count)].Name); birthUsed = true; } else // joined if (rnd.NextDouble() < 2496 / total && !birthUsed) { query.Add("joined", storage.JoinYears[getRandom(1, storage.JoinYears.Count)].Name); birthUsed = true; } // sex if (rnd.NextDouble() < 911 / total) { query.Add("sex", getRandom(new[] { Storage.s_Male, Storage.s_Female })); } // country if (rnd.NextDouble() < 776 / total && !cityUsed) { query.Add("country", storage.Countries[getRandom(1, storage.Countries.Count)].Name); countryUsed = true; } // country if (rnd.NextDouble() < 737 / total && !cityUsed) { query.Add("country", storage.Countries[getRandom(1, storage.Countries.Count)].Name); cityUsed = true; } // interests if (rnd.NextDouble() < 948 / total) { query.Add("interests", storage.Interests[getRandom(1, storage.Interests.Count)].Name); } // likes_contains if (rnd.NextDouble() < 1482 / total) { query.Add("likes", getRandom(1, Storage.MAX_ACCOUNTS)); } var queryStr = query.ToString(); var statusCode = router.getGroup.Process(ctx, 0); if (statusCode != 200) { router.getGroup.Process(ctx, 0); // debug } }
// main routing code (must be already serialized and ordered for POSTs!) public int ProcessRequest(HttpCtx ctx) { lastCall = Stats.Watch.Elapsed; // fill the header Array.Copy(responseHeaders, 0, ctx.Buffer, ctx.ResponseStart, responseHeaders.Length); ctx.ResponseBodyStart = ctx.ResponseStart + responseHeaders.Length; // parse the 1st header, parts[0]=method, parts[1]=path+params, path[2]="HTTP/1.1" if (ctx.Path == null) { Log.Error("Path: {0}", ctx.Path); return(sendReply(ctx, 400)); } var path = ctx.Path.Split('/'); if (path.Length < 4 || path[1] != "accounts") { return(sendReply(ctx, 404)); } if (ctx.Method == "GET") { Interlocked.Increment(ref getCounter); // /accounts/filter/ if (path[2] == "filter") { if (!path[3].IsEmpty) { return(sendReply(ctx, 404)); } else { return(sendReply(ctx, getFilter.Process(ctx, 0))); } } // /accounts/group/ if (path[2] == "group") { if (!path[3].IsEmpty) { return(sendReply(ctx, 404)); } else { return(sendReply(ctx, getGroup.Process(ctx, 0))); } } // /accounts/{id}/... if (path.Length < 5) { return(sendReply(ctx, 404)); } if (!path[2].TryToInt(out var id)) { return(sendReply(ctx, 404)); } // accounts/{id}/recommend/ if (path[3] == "recommend") { return(sendReply(ctx, getRecommend.Process(ctx, id))); } // accounts/{id}/suggest/ if (path[3] == "suggest") { return(sendReply(ctx, getSuggest.Process(ctx, id))); } // no other GETs supported return(sendReply(ctx, 404)); } if (ctx.Method == "POST") { Interlocked.Increment(ref postCounter); // /accounts/new/ if (path[2] == "new") { if (!path[3].IsEmpty) { return(sendReply(ctx, 404)); } else { return(sendReply(ctx, postNew.Process(ctx, 0))); } } // /accounts/likes/ if (path[2] == "likes") { if (!path[3].IsEmpty) { return(sendReply(ctx, 404)); } else { return(sendReply(ctx, postLikes.Process(ctx, 0))); } } // /accounts/{id}/ if (path[2].TryToInt(out var id)) { if (!path[3].IsEmpty) { return(sendReply(ctx, 404)); } else { return(sendReply(ctx, postUpdate.Process(ctx, id))); } } // no other POSTs supported return(sendReply(ctx, 404)); } // all other methods are not supported return(sendReply(ctx, 404)); }
// synchronously process the request, fill up responseBuffer, and return statusCode public int Process(HttpCtx ctx, int id) { var startTime = Stats.Watch.Elapsed; var limit = 0; if (!Mapper.ExtIdToIntId(id, out id)) { return(404); // no mapping found } var acct = store.Accounts[id]; if (acct.IsEmpty()) { return(404); // no such user } var flags = new SuggestQueryMask(); var cityIdx = 0; var countryIdx = 0; bool empty = false; foreach (var query in ctx.Params) { var value = query.Value; if (value.IsEmpty) { return(400); } if (query.Key == "query_id") { } // ignore else if (query.Key == "limit") { if (!value.TryToInt(out limit)) { return(400); } } else if (query.Key == "country") { if (value.IsEmpty) { return(400); } if (store.Countries.TryGetValue(value, out IRange countryInd)) { countryIdx = countryInd.Index; } else { empty = true; } flags |= SuggestQueryMask.Country; } else if (query.Key == "city") { if (value.IsEmpty) { return(400); } if (store.Cities.TryGetValue(value, out var cityBm)) { cityIdx = cityBm.Index; } else { empty = true; } flags |= SuggestQueryMask.City; } else // all other parameters are invalid { return(400); } } if (limit <= 0) { return(400); } if (empty || acct.LikesCount == 0) // shortcut { return(211); // empty accounts } // first, create the list of suggesters and find their similarity value var acctLikes = acct.GetLikes(store); if (!Pool <List <(int id, double sim)> > .TryGet(out var suggesters)) { suggesters = new List <(int id, double sim)>(4096); } for (int i = 0; i < acctLikes.Count; i++) { var q = store.Accounts[acctLikes[i].GetId()]; foreach (var suggester in q.GetLikedBy(store)) { var a = store.Accounts[suggester]; if (suggester != id && // can't suggest to myself a.IsMale() == acct.IsMale() && // suggester must be same gender (cityIdx == 0 || cityIdx == a.CityIdx) && // from the specified city (countryIdx == 0 || countryIdx == a.CountryIdx)) // from the specified country { #if false long key = id < suggester ? (id + ((long)suggester << 32)) : (suggester + ((long)id << 32)); if (!store.CachedSim.TryGetValue(key, out var similarity)) { // if it's a new suggester, calculate his similarity similarity = calcSimilarity(acctLikes, a.GetLikes(store)); store.CachedSim.Add(key, similarity); } #else // if it's a new suggester, calculate his similarity var similarity = calcSimilarity(acctLikes, a.GetLikes(store)); //store.CachedSim.Add(key, similarity); #endif if (similarity > 0) { suggesters.Add((suggester, similarity)); } } } } // suggesters is sorted by id, now, sort it by descending similarity then by ascending ids suggesters.Sort((x, y) => y.sim.CompareTo(x.sim)); // compose the response var sb = new AStringBuilder(ctx.Buffer, ctx.ResponseBodyStart); sb.Append("{\"accounts\":["); bool firstEl = true; // form the list of suggestions var suggestions = new List <int>(limit); var lastSuggester = 0; foreach (var kv in suggesters) { if (kv.id == lastSuggester) { continue; } else { lastSuggester = kv.id; } var a = store.Accounts[kv.id]; var aLikes = a.GetLikes(store); // now, add suggested likes that were not yet liked by acct for (int k = aLikes.Count - 1; k >= 0; k--) { var l0 = aLikes[k]; if (l0.GetId() == id) { continue; } var j1 = Array.BinarySearch(store.Likes, acct.LikesIdx, acct.LikesCount, l0, Like.CompareById); if (j1 < 0) // suggest only not already liked accounts { if (!suggestions.Contains(l0.GetId())) { suggestions.Add(l0.GetId()); outputAccount(l0.GetId(), sb, ref firstEl); if (suggestions.Count == limit) { break; } } } } if (suggestions.Count >= limit) { break; } } suggesters.Clear(); Pool <List <(int, double)> > .Release(suggesters); // finalize the output sb.Append("]}"); ctx.ResponseBodyLength = sb.Count; var stopTime = Stats.Watch.Elapsed; ctx.ContextType = "GetSuggest"; return(200); }
// synchronously process the request from requestBuffer, and return statusCode public int Process(HttpCtx ctx, int dummy) { var startTime = Stats.Watch.Elapsed; // path sanity check foreach (var query in ctx.Params) { var value = query.Value; if (value.IsEmpty) { return(400); } if (query.Key != "query_id") { // all other parameters are invalid return(400); } } // load the body if (ctx.RequestBodyStart == ctx.ResponseBodyStart) { return(400); } // parse Json and process dto var dto = DtoAccount.Obtain(); int statusCode = 400; try { JsonReader reader = new JsonReader(ctx.Buffer, ctx.RequestBodyStart); if (DtoAccount.Parse(ref reader, dto, store) && dto.flags != 0) { // add the new account statusCode = store.ValidateNewAccount(dto); if (statusCode == 201) { ctx.PostAction = () => { store.PostNewAccount(dto); DtoAccount.Release(dto); } } ; } } catch (Exception) { // fall through } // return the borrowed object if (ctx.PostAction == null) { DtoAccount.Release(dto); } var stopTime = Stats.Watch.Elapsed; ctx.ContextType = "PostNew"; return(statusCode); }