public ClientSideTypeDescription RegisterType(Type type, bool forceReindex = false) { if (type == null) { throw new ArgumentNullException(nameof(type)); } var typeDescription = ClientSideTypeDescription.RegisterType(type); KnownTypes[typeDescription.FullTypeName] = typeDescription; var request = new RegisterTypeRequest(typeDescription.AsTypeDescription, ShardIndex, ShardsCount); var response = Channel.SendRequest(request); if (response is ExceptionResponse exResponse) { throw new CacheException("Error while registering a type on the server", exResponse.Message, exResponse.CallStack); } return(typeDescription); }
/// <summary> /// Explicitly registers a type on the client and the server. In order to use this version of the method /// the type need to be tagged(attributes need to be associated to its public properties used as keys) /// Explicit type registration is not required. /// It is done automatically when the first Put() is executed for an item of the specified type /// or when a query is first built /// <br /> /// As type registration is an expensive operation, you may want to do it during the client initialization. /// </summary> /// <param name="type"></param> public ClientSideTypeDescription RegisterTypeIfNeeded(Type type) { if (type == null) { throw new ArgumentNullException(nameof(type)); } if (KnownTypes.TryGetValue(type.FullName ?? throw new InvalidOperationException(), out var typeDescription)) { return(typeDescription); } typeDescription = ClientSideTypeDescription.RegisterType(type); KnownTypes[typeDescription.FullTypeName] = typeDescription; var request = new RegisterTypeRequest(typeDescription.AsTypeDescription, ShardIndex, ShardsCount); var response = Channel.SendRequest(request); if (response is ExceptionResponse exResponse) { throw new CacheException("Error while registering a type on the server", exResponse.Message, exResponse.CallStack); } return(typeDescription); }
public void InitializeFromDump(string path) { path = DumpHelper.NormalizeDumpPath(path); var schemaPath = Path.Combine(path, "schema.json"); var json = File.ReadAllText(schemaPath); var schema = SerializationHelper.DeserializeJson <Schema>(json); foreach (var typeDescription in schema.TypeDescriptions) { // register the type on the server var shard = 0; foreach (var client in CacheClients) { var request = new RegisterTypeRequest(typeDescription, shard, CacheClients.Count); var response = client.Channel.SendRequest(request); if (response is ExceptionResponse exResponse) { throw new CacheException("Error while registering a type on the server", exResponse.Message, exResponse.CallStack); } shard++; } FeedMany(DumpHelper.ObjectsInDump(path, typeDescription), true); } // reinitialize the sequences. As the shard count has probably changed reinitialize all the sequences in each shard // starting with the maximum value var maxValues = new Dictionary <string, int>(); var files = Directory.EnumerateFiles(path, "sequence_*.json"); foreach (var file in files) { var sequenceJson = File.ReadAllText(file); var seq = SerializationHelper.DeserializeJson <Dictionary <string, int> >(sequenceJson); foreach (var pair in seq) { var keyFound = maxValues.ContainsKey(pair.Key); if (keyFound && maxValues[pair.Key] < pair.Value || !keyFound) { maxValues[pair.Key] = pair.Value; } } } // resync sequences on the server ResyncUniqueIds(maxValues); }
public void StreamUnstreamMessagesOneByOne() { var schema = TypedSchemaFactory.FromType(typeof(CacheableTypeOk)); var qbuilder = new QueryBuilder(typeof(CacheableTypeOk)); var put = new PutRequest(typeof(CacheableTypeOk)); var item = new CacheableTypeOk(3, 1003, "AHA", new DateTime(2010, 10, 02), 8); var typeDescription = TypedSchemaFactory.FromType(typeof(CacheableTypeOk)); put.Items.Add(PackedObject.Pack(item, schema)); var remove = new RemoveRequest(typeof(CacheableTypeOk), new KeyValue(1, schema.PrimaryKeyField)); var register = new RegisterTypeRequest(typeDescription); using (var stream = new MemoryStream()) { //request Streamer.ToStream(stream, new GetRequest(qbuilder.FromSql("select from CacheableTypeOk where IndexKeyValue > 1000"))); Streamer.ToStream(stream, put); Streamer.ToStream(stream, remove); Streamer.ToStream(stream, register); //response Streamer.ToStream(stream, new NullResponse()); Streamer.ToStream(stream, new ExceptionResponse(new Exception("fake exception"))); Streamer.ToStream(stream, new ServerDescriptionResponse()); stream.Seek(0, SeekOrigin.Begin); object reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is GetRequest); //request reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is PutRequest); reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is RemoveRequest); reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is RegisterTypeRequest); ////response reloaded = Streamer.FromStream <Response>(stream); Assert.IsTrue(reloaded is NullResponse); reloaded = Streamer.FromStream <Response>(stream); Assert.IsTrue(reloaded is ExceptionResponse); reloaded = Streamer.FromStream <Response>(stream); Assert.IsTrue(reloaded is ServerDescriptionResponse); } }
/// <summary> /// Creates the associated <see cref="DataStore" /> for new cacheable type /// </summary> /// <param name="request"></param> /// <param name="client"></param> private void RegisterType(RegisterTypeRequest request, IClient client) { try { var typeDescription = request.CollectionSchema; var collectionName = typeDescription.CollectionName; var dataStore = DataStores.TryGetValue(collectionName); if (ShardCount == 0) // not initialized { ShardIndex = request.ShardIndex; ShardCount = request.ShardsInCluster; } else // check it didn't change { if (ShardIndex != request.ShardIndex || ShardCount != request.ShardsInCluster) { throw new NotSupportedException( $"Cluster configuration changed. This node was shard {ShardIndex} / {ShardCount} and now is {request.ShardIndex} / {request.ShardsInCluster}"); } } if (dataStore != null) //type already registered { //if the type description changed reindex if (!typeDescription.Equals(dataStore.CollectionSchema)) { var newDataStore = DataStore.Reindex(dataStore, typeDescription); DataStores[collectionName] = newDataStore; _serviceContainer.SchemaPersistence.SaveSchema(GenerateSchema()); } } else // new type, store it in the type dictionary and initialize its DataStore { var newDataStore = new DataStore(typeDescription, new NullEvictionPolicy(), _serviceContainer.NodeConfig.FullTextConfig); DataStores.Add(collectionName, newDataStore); _serviceContainer.SchemaPersistence.SaveSchema(GenerateSchema()); } client?.SendResponse(new NullResponse()); } catch (Exception e) { client?.SendResponse(new ExceptionResponse(e)); } }
/// <summary> /// Creates the associated <see cref="DataStore" /> for new cacheable type /// </summary> /// <param name="request"></param> /// <param name="client"></param> private void RegisterType(RegisterTypeRequest request, IClient client) { if (client != null) // client request { ProcessRegisterType(request, client); } else // called internally (while loading data) { InternalProcessRegisterType(request); } }
public void StreamUnstreamMessagesOneByOne() { QueryBuilder qbuilder = new QueryBuilder(typeof(CacheableTypeOk)); PutRequest put = new PutRequest(typeof(CacheableTypeOk)); CacheableTypeOk item = new CacheableTypeOk(3, 1003, "AHA", new DateTime(2010, 10, 02), 8); TypeDescription typeDescription = ClientSideTypeDescription.RegisterType(typeof(CacheableTypeOk)).AsTypeDescription; put.Items.Add(CachedObject.Pack(item)); RemoveRequest remove = new RemoveRequest(typeof(CacheableTypeOk), typeDescription.MakePrimaryKeyValue(1)); RegisterTypeRequest register = new RegisterTypeRequest(typeDescription); using (MemoryStream stream = new MemoryStream()) { //request Streamer.ToStream(stream, new GetRequest(qbuilder.GetManyWhere("IndexKeyValue > 1000"))); Streamer.ToStream(stream, put); Streamer.ToStream(stream, remove); Streamer.ToStream(stream, register); //response Streamer.ToStream(stream, new NullResponse()); Streamer.ToStream(stream, new ExceptionResponse(new Exception("fake exception"))); Streamer.ToStream(stream, new ServerDescriptionResponse()); stream.Seek(0, SeekOrigin.Begin); object reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is GetRequest); //request reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is PutRequest); reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is RemoveRequest); reloaded = Streamer.FromStream <Request>(stream); Assert.IsTrue(reloaded is RegisterTypeRequest); ////response reloaded = Streamer.FromStream <Response>(stream); Assert.IsTrue(reloaded is NullResponse); reloaded = Streamer.FromStream <Response>(stream); Assert.IsTrue(reloaded is ExceptionResponse); reloaded = Streamer.FromStream <Response>(stream); Assert.IsTrue(reloaded is ServerDescriptionResponse); } }
private void InternalProcessRegisterType(RegisterTypeRequest request) { var typeDescription = request.TypeDescription; if (ShardCount == 0) // not initialized { ShardIndex = request.ShardIndex; ShardCount = request.ShardsInCluster; } else // check it didn't change { if (ShardIndex != request.ShardIndex || ShardCount != request.ShardsInCluster) { throw new NotSupportedException( $"Cluster configuration changed. This node was shard {ShardIndex} / {ShardCount} and now is {request.ShardIndex} / {request.ShardsInCluster}"); } } if (_knownTypes.ContainsKey(typeDescription.FullTypeName)) //type already registered { //check that the type description is the same if (!typeDescription.Equals(_knownTypes[typeDescription.FullTypeName])) { var message = $"The type {typeDescription.FullTypeName} is already registered but the type description is different"; throw new NotSupportedException(message); } } else // new type, store it in the type dictionary and initialize its DataStore { _knownTypes.Add(typeDescription.FullTypeName, typeDescription); PersistenceEngine?.UpdateSchema(GenerateSchema()); var cfg = Config.ConfigByType.ContainsKey(typeDescription.FullTypeName) ? Config.ConfigByType[typeDescription.FullTypeName] : new ServerDatastoreConfig(); var evictionPolicy = EvictionPolicyFactory.CreateEvictionPolicy(cfg.Eviction); var newDataStore = new DataStore(typeDescription, evictionPolicy); Dbg.CheckThat(Profiler != null); newDataStore.Profiler = Profiler; DataStores.Add(typeDescription.FullTypeName, newDataStore); } }
private void ProcessRegisterType(RegisterTypeRequest request, IClient client) { lock (DataStores) { try { InternalProcessRegisterType(request); client.SendResponse(new NullResponse()); } catch (Exception e) { client.SendResponse(new ExceptionResponse(e)); } } }
public void DeclareCollection(string collectionName, CollectionSchema schema, int shard = -1) { // do not modify the original schema = schema.Clone(); schema.CollectionName = collectionName; var request = new RegisterTypeRequest(schema, shard == -1 ? ShardIndex:shard, ShardsCount); var response = Channel.SendRequest(request); if (response is ExceptionResponse exResponse) { throw new CacheException("Error while registering a type on the server", exResponse.Message, exResponse.CallStack); } }
/// <summary> /// Register a type as cacheable with an external description /// Cacheable type descriptions can be provided by attributes on the public properties /// or as <see cref="TypeDescriptionConfig" />. /// If an external description is required, the type must be explicitly registered. /// </summary> /// <param name="type"></param> /// <param name="description"></param> public ClientSideTypeDescription RegisterTypeIfNeeded(Type type, TypeDescriptionConfig description) { if (KnownTypes.TryGetValue(description.FullTypeName, out var typeDescription)) { return(typeDescription); } typeDescription = ClientSideTypeDescription.RegisterType(type, description); KnownTypes[typeDescription.FullTypeName] = typeDescription; var request = new RegisterTypeRequest(typeDescription.AsTypeDescription, ShardIndex, ShardsCount); var response = Channel.SendRequest(request); if (response is ExceptionResponse exResponse) { throw new CacheException("Error while registering a type on the server", exResponse.Message, exResponse.CallStack); } return(typeDescription); }