コード例 #1
0
        /// <summary>
        ///     Processes all storage requests.
        /// </summary>
        private void ProcessStorageRequests()
        {
            DBResults   results;
            bool        storageUpdated = false;

            // Delete all storage requests that have finished and who's arbitrator has disconnected.
            m_databaseConnection.Query(@"DELETE FROM 
	                                        {0} 
                                        WHERE 
	                                        (success=1 OR failed=1) AND
	                                        (Select
		                                        COUNT(*)
	                                            FROM 
		                                        {1} AS b
                                                WHERE 
		                                        id=recieved_arbitrator_id) = 0 ",
                                        Settings.DB_TABLE_PENDING_STORE_REQUESTS,
                                        Settings.DB_TABLE_ACTIVE_ARBITRATORS);

            // Lock tables.
            m_databaseConnection.Query("LOCK TABLES {0} WRITE, {1} WRITE",
                                       Settings.DB_TABLE_PENDING_STORE_REQUESTS,
                                       Settings.DB_TABLE_ACCOUNTS);

            // Lets have a look at all requests and see if we find any we can commit.
            results = m_databaseConnection.Query(@"SELECT *, UNIX_TIMESTAMP()-recieved_time FROM {0} WHERE 
                                                        success=0 AND 
                                                        failed=0",
                                                   Settings.DB_TABLE_PENDING_STORE_REQUESTS);

            // Group together rows by zone id / client id.
            List<int> updated_ids = new List<int>();

            for (int i = 0; i < results.RowsAffected; i++)
            {
                DBRow row = results[i];

                // Ignore this request if we have already processed it.
                if (updated_ids.Contains((int)row["id"]))
                {
                    continue;
                }

                // Make a list of requests to update same client/zone.
                List<DBRow> sameRows = new List<DBRow>();
                sameRows.Add(row);
                updated_ids.Add((int)row["id"]);

                // Look for other rows affecting the same zone and client.
                int oldest_row_elapsed = 0;
                for (int k = 0; k < results.RowsAffected; k++)
                {
                    DBRow subrow = results[k];

                    // Ignore this request if we have already processed it.
                    if (updated_ids.Contains((int)subrow["id"]))
                    {
                        continue;
                    }

                    if ((int)row["client_id"] == (int)subrow["client_id"] &&
                        (int)row["zone_id"] == (int)subrow["zone_id"])
                    {
                        // Store oldest elapsed time for rows.
                        int subrow_elapsed = (int)(long)row["UNIX_TIMESTAMP()-recieved_time"];
                        if (subrow_elapsed > oldest_row_elapsed)
                        {
                            oldest_row_elapsed = subrow_elapsed;
                        }
                        
                        sameRows.Add(subrow);
                        updated_ids.Add((int)subrow["id"]);
                    }
                }

                // Do we have enough rows to commit.
                if (sameRows.Count >= Settings.ZoneSuperPeerCount || 
                    oldest_row_elapsed > Settings.STORE_REQUEST_TIMEOUT_INTERVAL / 1000)
                {
                    Logger.Info("Found {0} matching storage requests for client #{1} in zone #{2}.",
                                LoggerVerboseLevel.High,
                                sameRows.Count,
                                row["client_id"],
                                row["zone_id"]);

                    // Find the request with the most number of similar requests. This
                    // is the row we will consider the correct row.
                    int mostSimilarIndex = -1;
                    int mostSimilarCount = 0;
                    int mostSimilarSuperPeerID= 0;
                    UserAccountPersistentState mostSimilarState = null;

                    for (int j = 0; j < sameRows.Count; j++)
                    {
                        UserAccountPersistentState state1 = new UserAccountPersistentState();
                        state1.Deserialize((byte[])sameRows[j]["state"]);

                        // Count number of similar row.
                        int similarCount = 1;
                        for (int l = 0; l < sameRows.Count; l++)
                        {
                            if (j == l) continue;

                            UserAccountPersistentState state2 = new UserAccountPersistentState();
                            state2.Deserialize((byte[])sameRows[l]["state"]);

                            if (state1.IsSimilarTo(state2))
                            {
                                similarCount++;
                            }
                        }

                        // Is this the most similar state so far?
                        if (similarCount > mostSimilarCount || (similarCount == mostSimilarCount && (int)sameRows[j]["superpeer_id"] < mostSimilarSuperPeerID))
                        {
                            mostSimilarState = state1;
                            mostSimilarIndex = j;
                            mostSimilarCount = similarCount;
                            mostSimilarSuperPeerID = (int)sameRows[j]["superpeer_id"];
                        }
                    }

                    // If we only have a maximum of 1 match, everyone fails, we can't have
                    // one user being authorative.
                    if (mostSimilarCount <= 1)
                    {
                        Logger.Info("Of {0} matching storage requests for client #{1} in zone #{2}, only {3} were similar. Store request rejected.",
                                    LoggerVerboseLevel.Normal,
                                    sameRows.Count,
                                    row["client_id"],
                                    row["zone_id"],
                                    mostSimilarCount);

                        m_databaseConnection.Query("UPDATE {0} SET failed=1 WHERE client_id={1} AND zone_id={2}",
                                                   Settings.DB_TABLE_PENDING_STORE_REQUESTS,
                                                   row["client_id"],
                                                   row["zone_id"]);

                        storageUpdated = true;
                    }
                    else
                    {
                        Logger.Info("Of {0} matching storage requests for client #{1} in zone #{2}, {3} were similar. Store request was accepted.",
                                    LoggerVerboseLevel.High,
                                    sameRows.Count,
                                    row["client_id"],
                                    row["zone_id"],
                                    mostSimilarCount);

                        // Update state of storage requests.
                        for (int j = 0; j < sameRows.Count; j++)
                        {
                            UserAccountPersistentState state2 = new UserAccountPersistentState();
                            state2.Deserialize((byte[])sameRows[j]["state"]);

                            // If its similar to the correct state, success!
                            if (state2.IsSimilarTo(mostSimilarState))
                            {
                                m_databaseConnection.Query("UPDATE {0} SET success=1 WHERE id={1}",
                                                           Settings.DB_TABLE_PENDING_STORE_REQUESTS,
                                                           sameRows[j]["id"]);

                                Logger.Info("Storage request by SuperPeer #{0} for Client #{1} in Zone #{2} was similar to correct states and was accepted.",
                                    LoggerVerboseLevel.High,
                                    sameRows[j]["superpeer_id"],
                                    sameRows[j]["client_id"],
                                    sameRows[j]["zone_id"]);
                            }

                            // Otherwise failure :(.
                            else
                            {
                                m_databaseConnection.Query("UPDATE {0} SET failed=1 WHERE id={1}",
                                                           Settings.DB_TABLE_PENDING_STORE_REQUESTS,
                                                           sameRows[j]["id"]);

                                Logger.Info("Storage request by SuperPeer #{0} for Client #{1} in Zone #{2} was not similar to correct states, and was ignored.",
                                            LoggerVerboseLevel.Normal,
                                            sameRows[j]["superpeer_id"],
                                            sameRows[j]["client_id"],
                                            sameRows[j]["zone_id"]);
                            }
                        }

                        // Now actually store the data.
                        m_databaseConnection.QueryParameterized("UPDATE {0} SET persistent_state=@parameter_1 WHERE id={1}",
                                                                 new object[] { mostSimilarState.Serialize() },
                                                                 Settings.DB_TABLE_ACCOUNTS,
                                                                 row["account_id"]);
                        storageUpdated = true;
                    }
                }
            }

            // Dispose of timed out requests.
            
            results = m_databaseConnection.Query(@"UPDATE {0} SET failed=1 WHERE 
                                                   UNIX_TIMESTAMP() - recieved_time > {1}",
                                                  Settings.DB_TABLE_PENDING_STORE_REQUESTS,
                                                  Settings.STORE_REQUEST_TIMEOUT_INTERVAL / 1000);
            if (results.RowsAffected > 0)
            {
                storageUpdated = true;
            }

            // Unlock tables.
            m_databaseConnection.Query("UNLOCK TABLES");
        }
コード例 #2
0
        /// <summary>
        ///     Checks if this persistent state is similar enough to another state that it 
        ///     can be considered the same.
        /// </summary>
        /// <param name="state">Other state to check.</param>
        /// <returns>True if states are similar, otherwise false.</returns>
        public bool IsSimilarTo(UserAccountPersistentState state)
        {
            Type type = this.GetType();

            foreach (FieldInfo info in type.GetFields())
            {
                object val1                         = info.GetValue(this);
                object val2                         = info.GetValue(state);

                SimilarityThresholdAttribute attr   = info.GetCustomAttribute(typeof(SimilarityThresholdAttribute)) as SimilarityThresholdAttribute;

                if (attr != null)
                {
                    if (attr.CompareValues(val1, val2) == false)
                    {
                        return false;
                    }
                }
            }

            return true;
        }