Example #1
0
        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
            }
        }
Example #2
0
        public void ProcessWarmup()
        {
            var ctx = HttpCtx.Obtain();

            warmer.GetOnce(ctx, warmId++);
            HttpCtx.Release(ctx);
        }
Example #3
0
        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
            }
        }
Example #4
0
 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);
         }
     }
 }
Example #5
0
        // 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);
        }
Example #6
0
 public static HttpCtx Obtain()
 {
     if (!bag.TryTake(out var obj))
     {
         obj = new HttpCtx();
     }
     return(obj);
 }
Example #7
0
        /******************************** 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);
        }
Example #8
0
        public void RunGet(TimeSpan warmupDeadline)
        {
            HttpCtx ctx      = new HttpCtx();
            int     query_id = 0;

            while (Stats.Watch.Elapsed < warmupDeadline)
            {
                GetOnce(ctx, query_id++);
            }
        }
Example #9
0
        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;
        }
Example #10
0
        // 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);
        }
Example #11
0
        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;
        }
Example #12
0
        // 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);
        }
Example #13
0
        // 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);
        }
Example #14
0
        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
            }
        }
Example #15
0
        // 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);
        }
Example #16
0
        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);
        }
Example #17
0
 public static void Release(HttpCtx bb)
 {
     bb.Reset();
     bag.Add(bb);
 }
Example #18
0
        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
            }
        }
Example #19
0
        // 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));
        }
Example #20
0
        // 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);
        }
Example #21
0
        // 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);
        }