aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Data/MySQL/MySQLInventoryData.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Data/MySQL/MySQLInventoryData.cs')
-rw-r--r--OpenSim/Data/MySQL/MySQLInventoryData.cs113
1 files changed, 108 insertions, 5 deletions
diff --git a/OpenSim/Data/MySQL/MySQLInventoryData.cs b/OpenSim/Data/MySQL/MySQLInventoryData.cs
index 0fb49c1..59d7858 100644
--- a/OpenSim/Data/MySQL/MySQLInventoryData.cs
+++ b/OpenSim/Data/MySQL/MySQLInventoryData.cs
@@ -704,13 +704,116 @@ namespace OpenSim.Data.MySQL
704 /// <returns></returns> 704 /// <returns></returns>
705 public List<InventoryFolderBase> getFolderHierarchy(LLUUID parentID) 705 public List<InventoryFolderBase> getFolderHierarchy(LLUUID parentID)
706 { 706 {
707 List<InventoryFolderBase> folders = new List<InventoryFolderBase>(); 707 /* Note: There are subtle changes between this implementation of getFolderHierarchy and the previous one
708 getInventoryFolders(ref folders, parentID); 708 * - We will only need to hit the database twice instead of n times.
709 * - We assume the database is well-formed - no stranded/dangling folders, all folders in heirarchy owned
710 * by the same person, each user only has 1 inventory heirarchy
711 * - The returned list is not ordered, instead of breadth-first ordered
712 There are basically 2 usage cases for getFolderHeirarchy:
713 1) Getting the user's entire inventory heirarchy when they log in
714 2) Finding a subfolder heirarchy to delete when emptying the trash.
715 This implementation will pull all inventory folders from the database, and then prune away any folder that
716 is not part of the requested sub-heirarchy. The theory is that it is cheaper to make 1 request from the
717 database than to make n requests. This pays off only if requested heirarchy is large.
718 By making this choice, we are making the worst case better at the cost of making the best case worse.
719 This way is generally better because we don't have to rebuild the connection/sql query per subfolder,
720 even if we end up getting more data from the SQL server than we need.
721 - Francis
722 */
723 try
724 {
725 List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
726 Dictionary<LLUUID, List<InventoryFolderBase>> hashtable
727 = new Dictionary<LLUUID, List<InventoryFolderBase>>(); ;
728 List<InventoryFolderBase> parentFolder = new List<InventoryFolderBase>();
729 lock (database)
730 {
731 MySqlCommand result;
732 MySqlDataReader reader;
733 bool buildResultsFromHashTable = false;
734
735 database.CheckConnection();
709 736
710 for (int i = 0; i < folders.Count; i++) 737 /* Fetch the parent folder from the database to determine the agent ID, and if
711 getInventoryFolders(ref folders, folders[i].ID); 738 * we're querying the root of the inventory folder tree */
739 result = new MySqlCommand("SELECT * FROM inventoryfolders WHERE folderID = ?uuid",
740 database.Connection);
741 result.Parameters.AddWithValue("?uuid", parentID.ToString());
742 reader = result.ExecuteReader();
743 while (reader.Read()) // Should be at most 1 result
744 parentFolder.Add(readInventoryFolder(reader));
745 reader.Close();
746 result.Dispose();
712 747
713 return folders; 748 if (parentFolder.Count >= 1) // No result means parent folder does not exist
749 {
750 if (parentFolder[0].ParentID == LLUUID.Zero) // We are querying the root folder
751 {
752 /* Get all of the agent's folders from the database, put them in a list and return it */
753 result = new MySqlCommand("SELECT * FROM inventoryfolders WHERE agentID = ?uuid",
754 database.Connection);
755 result.Parameters.AddWithValue("?uuid", parentFolder[0].Owner.ToString());
756 reader = result.ExecuteReader();
757 while (reader.Read())
758 {
759 InventoryFolderBase curFolder = readInventoryFolder(reader);
760 if (curFolder.ID != parentID) // Do not need to add the root node of the tree to the list
761 folders.Add(curFolder);
762 }
763 reader.Close();
764 result.Dispose();
765 } // if we are querying the root folder
766 else // else we are querying a subtree of the inventory folder tree
767 {
768 /* Get all of the agent's folders from the database, put them all in a hash table
769 * indexed by their parent ID */
770 result = new MySqlCommand("SELECT * FROM inventoryfolders WHERE agentID = ?uuid",
771 database.Connection);
772 result.Parameters.AddWithValue("?uuid", parentFolder[0].Owner.ToString());
773 reader = result.ExecuteReader();
774 while (reader.Read())
775 {
776 InventoryFolderBase curFolder = readInventoryFolder(reader);
777 if (hashtable.ContainsKey(curFolder.ParentID)) // Current folder already has a sibling
778 hashtable[curFolder.ParentID].Add(curFolder); // append to sibling list
779 else // else current folder has no known (yet) siblings
780 {
781 List<InventoryFolderBase> siblingList = new List<InventoryFolderBase>();
782 siblingList.Add(curFolder);
783 // Current folder has no known (yet) siblings
784 hashtable.Add(curFolder.ParentID, siblingList);
785 }
786 } // while more items to read from the database
787 reader.Close();
788 result.Dispose();
789
790 // Set flag so we know we need to build the results from the hash table after
791 // we unlock the database
792 buildResultsFromHashTable = true;
793
794 } // else we are querying a subtree of the inventory folder tree
795 } // if folder parentID exists
796
797 if (buildResultsFromHashTable)
798 {
799 /* We have all of the user's folders stored in a hash table indexed by their parent ID
800 * and we need to return the requested subtree. We will build the requested subtree
801 * by performing a breadth-first-search on the hash table */
802 if (hashtable.ContainsKey(parentID))
803 folders.AddRange(hashtable[parentID]);
804 for (int i = 0; i < folders.Count; i++) // **Note: folders.Count is *not* static
805 if (hashtable.ContainsKey(folders[i].ID))
806 folders.AddRange(hashtable[folders[i].ID]);
807 }
808 } // lock(database)
809 return folders;
810 }
811 catch (Exception e)
812 {
813 database.Reconnect();
814 m_log.Error(e.ToString());
815 return null;
816 }
714 } 817 }
715 818
716 /// <summary> 819 /// <summary>