/// <summary> /// Inserts an index entry for a single document into a single index using a long lived index page catalog. /// </summary> /// <param name="transaction"></param> /// <param name="schemaMeta"></param> /// <param name="indexMeta"></param> /// <param name="document"></param> private void InsertDocumentIntoIndex(Transaction transaction, PersistSchema schemaMeta, PersistIndex indexMeta, PersistDocument document, PersistIndexPageCatalog indexPageCatalog, bool flushPageCatalog) { try { var searchTokens = GetIndexSearchTokens(transaction, indexMeta, document); var findResult = FindKeyPage(transaction, indexMeta, searchTokens, indexPageCatalog); //If we found a full match for all supplied key values - add the document to the leaf collection. if (findResult.IsFullMatch) { if (findResult.Leaf.DocumentIDs == null) { findResult.Leaf.DocumentIDs = new HashSet <Guid>(); } if (indexMeta.IsUnique && findResult.Leaf.DocumentIDs.Count > 1) { string exceptionText = string.Format("Duplicate key violation occurred for index [{0}]/[{1}]. Values: {{{2}}}", schemaMeta.VirtualPath, indexMeta.Name, string.Join(",", searchTokens)); throw new DokdexDuplicateKeyViolation(exceptionText); } findResult.Leaf.DocumentIDs.Add(document.Id); if (flushPageCatalog) { core.IO.PutPBuf(transaction, indexMeta.DiskPath, findResult.Catalog); } } else { //If we didn't find a full match for all supplied key values, // then create the tree and add the document to the lowest leaf. //Note that we are going to start creating the leaf level at the findResult.ExtentLevel. // This is because we may have a partial match and don't need to create the full tree. lock (indexPageCatalog) { for (int i = findResult.ExtentLevel; i < searchTokens.Count; i++) { findResult.Leaf = findResult.Leaves.AddNewleaf(searchTokens[i]); findResult.Leaves = findResult.Leaf.Leaves; } if (findResult.Leaf.DocumentIDs == null) { findResult.Leaf.DocumentIDs = new HashSet <Guid>(); } findResult.Leaf.DocumentIDs.Add(document.Id); } if (flushPageCatalog) { core.IO.PutPBuf(transaction, indexMeta.DiskPath, findResult.Catalog); } } } catch (Exception ex) { core.Log.Write(String.Format("Index document insert failed for process {0}.", transaction.ProcessId), ex); throw; } }
/// <summary> /// Finds the appropriate index page for a set of key values using a long lived index page catalog. /// </summary> /// <param name="transaction"></param> /// <param name="indexMeta"></param> /// <param name="searchTokens"></param> /// <param name="indexPageCatalog"></param> /// <returns></returns> private FindKeyPageResult FindKeyPage(Transaction transaction, PersistIndex indexMeta, List <string> searchTokens, PersistIndexPageCatalog suppliedIndexPageCatalog) { try { var indexPageCatalog = suppliedIndexPageCatalog; if (indexPageCatalog == null) { indexPageCatalog = core.IO.GetPBuf <PersistIndexPageCatalog>(transaction, indexMeta.DiskPath, LockOperation.Write); } lock (indexPageCatalog) { FindKeyPageResult result = new FindKeyPageResult() { Catalog = indexPageCatalog }; result.Leaves = result.Catalog.Leaves; if (result.Leaves == null || result.Leaves.Count == 0) { //The index is empty. return(result); } int foundExtentCount = 0; foreach (var token in searchTokens) { bool locatedExtent = false; foreach (var leaf in result.Leaves) { if (leaf.Key == token) { locatedExtent = true; foundExtentCount++; result.Leaf = leaf; result.Leaves = leaf.Leaves; //Move one level lower in the extent tree. result.IsPartialMatch = true; result.ExtentLevel = foundExtentCount; if (foundExtentCount == searchTokens.Count) { result.IsPartialMatch = false; result.IsFullMatch = true; return(result); } } } if (locatedExtent == false) { return(result); } } return(result); } } catch (Exception ex) { core.Log.Write(String.Format("Failed to locate key page for process {0}.", transaction.ProcessId), ex); throw; } }