private static void ClearTokenByResourceId(SessionContainerState self, string resourceId) { if (!string.IsNullOrEmpty(resourceId)) { ResourceId resource = ResourceId.Parse(resourceId); if (resource.DocumentCollection != 0) { ulong rid = resource.UniqueDocumentCollectionId; self.rwlock.EnterWriteLock(); try { if (self.collectionResourceIdByName.ContainsKey(rid)) { string collectionName = self.collectionResourceIdByName[rid]; _ = self.sessionTokensRIDBased.TryRemove(rid, out _); _ = self.collectionResourceIdByName.TryRemove(rid, out _); _ = self.collectionNameByResourceId.TryRemove(collectionName, out _); } } finally { self.rwlock.ExitWriteLock(); } } } }
private static void ClearTokenByCollectionFullname(SessionContainerState self, string collectionFullname) { if (!string.IsNullOrEmpty(collectionFullname)) { string collectionName = PathsHelper.GetCollectionPath(collectionFullname); self.rwlock.EnterWriteLock(); try { if (self.collectionNameByResourceId.ContainsKey(collectionName)) { string ignoreString; ulong ignoreUlong; ulong rid = self.collectionNameByResourceId[collectionName]; ConcurrentDictionary <string, ISessionToken> ignored; self.sessionTokensRIDBased.TryRemove(rid, out ignored); self.collectionResourceIdByName.TryRemove(rid, out ignoreString); self.collectionNameByResourceId.TryRemove(collectionName, out ignoreUlong); } } finally { self.rwlock.ExitWriteLock(); } } }
private static string ResolvePartitionLocalSessionTokenForGateway(SessionContainerState self, DocumentServiceRequest request, string partitionKeyRangeId) { ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = SessionContainer.GetPartitionKeyRangeIdToTokenMap(self, request); if (partitionKeyRangeIdToTokenMap != null) { if (partitionKeyRangeIdToTokenMap.TryGetValue(partitionKeyRangeId, out ISessionToken sessionToken)) { return(partitionKeyRangeId + SessionContainer.sessionTokenSeparator + sessionToken.ConvertToString()); } else if (request.RequestContext.ResolvedPartitionKeyRange.Parents != null) { ISessionToken parentSessionToken = null; for (int parentIndex = request.RequestContext.ResolvedPartitionKeyRange.Parents.Count - 1; parentIndex >= 0; parentIndex--) { if (partitionKeyRangeIdToTokenMap.TryGetValue(request.RequestContext.ResolvedPartitionKeyRange.Parents[parentIndex], out sessionToken)) { // A partition can have more than 1 parent (merge). In that case, we apply Merge to generate a token with both parent's max LSNs parentSessionToken = parentSessionToken != null?parentSessionToken.Merge(sessionToken) : sessionToken; } } // When we don't have the session token for a partition, we can leverage the session token of the parent(s) if (parentSessionToken != null) { return(partitionKeyRangeId + SessionContainer.sessionTokenSeparator + parentSessionToken.ConvertToString()); } } } return(null); }
private static string ResolvePartitionLocalSessionTokenForGateway(SessionContainerState self, DocumentServiceRequest request, string partitionKeyRangeId) { ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = SessionContainer.GetPartitionKeyRangeIdToTokenMap(self, request); if (partitionKeyRangeIdToTokenMap != null) { if (partitionKeyRangeIdToTokenMap.TryGetValue(partitionKeyRangeId, out ISessionToken sessionToken)) { return(partitionKeyRangeId + ":" + sessionToken.ConvertToString()); } else if (request.RequestContext.ResolvedPartitionKeyRange.Parents != null) { for (int parentIndex = request.RequestContext.ResolvedPartitionKeyRange.Parents.Count - 1; parentIndex >= 0; parentIndex--) { if (partitionKeyRangeIdToTokenMap.TryGetValue(request.RequestContext.ResolvedPartitionKeyRange.Parents[parentIndex], out sessionToken)) { return(partitionKeyRangeId + ":" + sessionToken.ConvertToString()); } } } } return(null); }
private static void SetSessionToken(SessionContainerState self, string collectionRid, string collectionFullname, INameValueCollection responseHeaders) { ResourceId resourceId = ResourceId.Parse(collectionRid); string collectionName = PathsHelper.GetCollectionPath(collectionFullname); string token = responseHeaders[HttpConstants.HttpHeaders.SessionToken]; if (!string.IsNullOrEmpty(token)) { SessionContainer.SetSessionToken(self, resourceId, collectionName, token); } }
private static string ResolveGlobalSessionToken(SessionContainerState self, DocumentServiceRequest request) { ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = SessionContainer.GetPartitionKeyRangeIdToTokenMap(self, request); if (partitionKeyRangeIdToTokenMap != null) { return(SessionContainer.GetSessionTokenString(partitionKeyRangeIdToTokenMap)); } return(string.Empty); }
private static void SetSessionToken(SessionContainerState self, DocumentServiceRequest request, INameValueCollection responseHeaders) { string token = responseHeaders[HttpConstants.HttpHeaders.SessionToken]; if (!string.IsNullOrEmpty(token)) { if (SessionContainer.ShouldUpdateSessionToken(request, responseHeaders, out ResourceId resourceId, out string collectionName)) { SessionContainer.SetSessionToken(self, resourceId, collectionName, token); } } }
private static SessionContainerSnapshot MakeSnapshot(SessionContainerState self) { self.rwlock.EnterReadLock(); try { return(new SessionContainerSnapshot(self.collectionNameByResourceId, self.collectionResourceIdByName, self.sessionTokensRIDBased)); } finally { self.rwlock.ExitReadLock(); } }
private static string GetSessionToken(SessionContainerState self, string collectionLink) { bool arePathSegmentsParsed = PathsHelper.TryParsePathSegments( collectionLink, out _, out _, out string resourceIdOrFullName, out bool isNameBased); ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null; if (arePathSegmentsParsed) { ulong?maybeRID = null; if (isNameBased) { string collectionName = PathsHelper.GetCollectionPath(resourceIdOrFullName); if (self.collectionNameByResourceId.TryGetValue(collectionName, out ulong rid)) { maybeRID = rid; } } else { ResourceId resourceId = ResourceId.Parse(resourceIdOrFullName); if (resourceId.DocumentCollection != 0) { maybeRID = resourceId.UniqueDocumentCollectionId; } } if (maybeRID.HasValue) { self.sessionTokensRIDBased.TryGetValue(maybeRID.Value, out partitionKeyRangeIdToTokenMap); } } if (partitionKeyRangeIdToTokenMap == null) { return(string.Empty); } return(SessionContainer.GetSessionTokenString(partitionKeyRangeIdToTokenMap)); }
private static void AddSessionToken(SessionContainerState self, ulong rid, string partitionKeyRangeId, ISessionToken token) { self.sessionTokensRIDBased.AddOrUpdate( rid, (ridKey) => { ConcurrentDictionary <string, ISessionToken> tokens = new ConcurrentDictionary <string, ISessionToken>(); tokens[partitionKeyRangeId] = token; return(tokens); }, (ridKey, tokens) => { tokens.AddOrUpdate( partitionKeyRangeId, token, (existingPartitionKeyRangeId, existingToken) => existingToken.Merge(token)); return(tokens); }); }
private static void AddSessionToken(SessionContainerState self, ulong rid, string partitionKeyRangeId, ISessionToken token) { // Avoid using GetOrAdd because it adds lock contention with the inner AddOrUpdate call if (!self.sessionTokensRIDBased.TryGetValue(rid, out ConcurrentDictionary <string, ISessionToken> tokens)) { tokens = new ConcurrentDictionary <string, ISessionToken>(); if (!self.sessionTokensRIDBased.TryAdd(rid, tokens)) { // Handle if there was a race condition and a different thread did // the add after the initial read if (!self.sessionTokensRIDBased.TryGetValue(rid, out tokens)) { throw new InternalServerErrorException("AddSessionToken failed to get or add the session token dictionary."); } } } tokens.AddOrUpdate( key: partitionKeyRangeId, addValue: token, updateValueFactory: (existingPartitionKeyRangeId, existingToken) => existingToken.Merge(token)); }
public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) { return(false); } SessionContainerState sibling = (SessionContainerState)obj; if (!AreDictionariesEqual(collectionNameByResourceId, sibling.collectionNameByResourceId, (x, y) => x == y)) { return(false); } if (!AreDictionariesEqual(collectionResourceIdByName, sibling.collectionResourceIdByName, (x, y) => x == y)) { return(false); } if (!AreDictionariesEqual(sessionTokensRIDBased, sibling.sessionTokensRIDBased, (x, y) => AreDictionariesEqual(x, y, (a, b) => a.Equals(b)))) { return(false); } return(true); }
public SessionContainer(string hostName) { this.state = new SessionContainerState(hostName); }
// State may be replaced (from a different thread) during an execution of an instance method so in a straightforward // implementation the method may acquire lock on the initial state but release it on an replaced state resulting in an // error. To avoid this situation a method reads state into a local variable then it works only with the variable; also // it explicitly passes it to the utility methods. We put all logic in static methods since static methods don't have // access to instance members it eliminates the problem of accidental accessing state the second time. public void ReplaceCurrrentStateWithStateOf(SessionContainer comrade) { this.state = comrade.state; }
private static void SetSessionToken(SessionContainerState self, ResourceId resourceId, string collectionName, string encodedToken) { string partitionKeyRangeId; ISessionToken token; if (VersionUtility.IsLaterThan(HttpConstants.Versions.CurrentVersion, HttpConstants.VersionDates.v2015_12_16)) { string[] tokenParts = encodedToken.Split(':'); partitionKeyRangeId = tokenParts[0]; token = SessionTokenHelper.Parse(tokenParts[1], HttpConstants.Versions.CurrentVersion); } else { //todo: elasticcollections remove after first upgrade. partitionKeyRangeId = "0"; token = SessionTokenHelper.Parse(encodedToken, HttpConstants.Versions.CurrentVersion); } DefaultTrace.TraceVerbose("Update Session token {0} {1} {2}", resourceId.UniqueDocumentCollectionId, collectionName, token); bool isKnownCollection = false; self.rwlock.EnterReadLock(); try { isKnownCollection = self.collectionNameByResourceId.TryGetValue(collectionName, out ulong resolvedCollectionResourceId) && self.collectionResourceIdByName.TryGetValue(resourceId.UniqueDocumentCollectionId, out string resolvedCollectionName) && resolvedCollectionResourceId == resourceId.UniqueDocumentCollectionId && resolvedCollectionName == collectionName; if (isKnownCollection) { SessionContainer.AddSessionToken(self, resourceId.UniqueDocumentCollectionId, partitionKeyRangeId, token); } } finally { self.rwlock.ExitReadLock(); } if (!isKnownCollection) { self.rwlock.EnterWriteLock(); try { if (self.collectionNameByResourceId.TryGetValue(collectionName, out ulong resolvedCollectionResourceId)) { _ = self.sessionTokensRIDBased.TryRemove(resolvedCollectionResourceId, out _); _ = self.collectionResourceIdByName.TryRemove(resolvedCollectionResourceId, out _); } self.collectionNameByResourceId[collectionName] = resourceId.UniqueDocumentCollectionId; self.collectionResourceIdByName[resourceId.UniqueDocumentCollectionId] = collectionName; SessionContainer.AddSessionToken(self, resourceId.UniqueDocumentCollectionId, partitionKeyRangeId, token); } finally { self.rwlock.ExitWriteLock(); } } }
private static ConcurrentDictionary <string, ISessionToken> GetPartitionKeyRangeIdToTokenMap(SessionContainerState self, DocumentServiceRequest request) { ulong?maybeRID = null; if (request.IsNameBased) { string collectionName = PathsHelper.GetCollectionPath(request.ResourceAddress); if (self.collectionNameByResourceId.TryGetValue(collectionName, out ulong rid)) { maybeRID = rid; } } else { if (!string.IsNullOrEmpty(request.ResourceId)) { ResourceId resourceId = ResourceId.Parse(request.ResourceId); if (resourceId.DocumentCollection != 0) { maybeRID = resourceId.UniqueDocumentCollectionId; } } } ConcurrentDictionary <string, ISessionToken> partitionKeyRangeIdToTokenMap = null; if (maybeRID.HasValue) { self.sessionTokensRIDBased.TryGetValue(maybeRID.Value, out partitionKeyRangeIdToTokenMap); } return(partitionKeyRangeIdToTokenMap); }
private static ISessionToken ResolvePartitionLocalSessionToken(SessionContainerState self, DocumentServiceRequest request, string partitionKeyRangeId) { return(SessionTokenHelper.ResolvePartitionLocalSessionToken(request, partitionKeyRangeId, SessionContainer.GetPartitionKeyRangeIdToTokenMap(self, request))); }