- 25 2月, 2020 2 次提交
-
-
由 eileencodes 提交于
Applications can now connect to multiple shards and switch between their shards in an application. Note that the shard swapping is still a manual process as this change does not include an API for automatic shard swapping. Usage: Given the following configuration: ```yaml production: primary: database: my_database primary_shard_one: database: my_database_shard_one ``` Connect to multiple shards: ```ruby class ApplicationRecord < ActiveRecord::Base self.abstract_class = true connects_to shards: { default: { writing: :primary }, shard_one: { writing: :primary_shard_one } } ``` Swap between shards in your controller / model code: ```ruby ActiveRecord::Base.connected_to(shard: :shard_one) do # Read from shard one end ``` The horizontal sharding API also supports read replicas. See guides for more details. This PR also moves some no-doc'd methods into the private namespace as they were unnecessarily public. We've updated some error messages and documentation. Co-authored-by: NJohn Crepezzi <john.crepezzi@gmail.com>
-
由 eileencodes 提交于
I have so. many. regrets. about using `spec_name` for database configurations and now I'm finally putting this mistake to an end. Back when I started multi-db work I assumed that eventually `connection_specification_name` (sometimes called `spec_name`) and `spec_name` for configurations would one day be the same thing. After 2 years I no longer believe they will ever be the same thing. This PR deprecates `spec_name` on database configurations in favor of `name`. It's the same behavior, just a better name, or at least a less confusing name. `connection_specification_name` refers to the parent class name (ie ActiveRecord::Base, AnimalsBase, etc) that holds the connection for it's models. In some places like ConnectionHandler it shortens this to `spec_name`, hence the major confusion. Recently I've been working with some new folks on database stuff and connection management and realize how confusing it was to explain that `db_config.spec_name` was not `spec_name` and `connection_specification_name`. Worse than that one is a symbole while the other is a class name. This was made even more complicated by the fact that `ActiveRecord::Base` used `primary` as the `connection_specification_name` until #38190. After spending 2 years with connection management I don't believe that we can ever use the symbols from the database configs as a way to connect the database without the class name being _somewhere_ because a db_config does not know who it's owner class is until it's been connected and a model has no idea what db_config belongs to it until it's connected. The model is the only way to tie a primary/writer config to a replica/reader config. This could change in the future but I don't see value in adding a class name to the db_configs before connection or telling a model what config belongs to it before connection. That would probably break a lot of application assumptions. If we do ever end up in that world, we can use name, because tbh `spec_name` and `connection_specification_name` were always confusing to me.
-
- 29 1月, 2020 1 次提交
-
-
由 eileencodes 提交于
Fixes #38332 If the `connected_to` block returns a relation and does not inspect, or load that relation before returning it, the block will exit before the database is queried. This causes the wrong database connection to be queried. The consequences of this are getting records from the primary instead of the replica, and potentially having database performance impact. Relations lazily query the database. If you return the relation from the block like: ``` posts = ActiveRecord::Base.connected_to(role: :reading) { Post.where(id: 1) } ``` `posts.first` will be queried from the `writing` connection instead because it's lazy and performed outside the block. Any query that loads the relation (ie `to_a`) inside the block would eagerly load the relation's records and not exhibit this bug. `connected_to` now checks if the return value is a `Relation` and if so calls `load`. Co-authored-by: NAaron Patterson <aaron.patterson@gmail.com>
-
- 22 1月, 2020 1 次提交
-
-
由 eileencodes 提交于
Calling `#remove_connection` on the handler is deprecated in favor of `#remove_connection_pool`. This change was made to support changing the return value from a hash to a `DatabaseConfig` object. `#remove_connection` will be removed in 6.2. NOTE: `#remove_connection` on `ActiveRecord::Base` will also now return a `DatabaseConfig` object. We didn't use a deprecation here since it's not documented that this method used to return a `Hash`. Co-authored-by: NJohn Crepezzi <john.crepezzi@gmail.com>
-
- 10 1月, 2020 1 次提交
-
-
由 eileencodes 提交于
Since test fixtures share connections (due to transactional tests) we end up overwriting the reading configuration so Rails doesn't recognize it as a replica connection. This change ensures that if we're using the `reading` role that connections will always have prevent writes turned on. If you need a replica connection that does not block writes, you should use a different role name other than `:reading`. The db selector test and connection handlers test have been updated to test for these changes. In the db selector test we don't always have a writing handler so I updated test fixtures to return if that's nil. Lastly one test needed to be updated to use a different handler name due to it needing to write to successfully test what it needs to test. Fixes #37765
-
- 09 1月, 2020 1 次提交
-
-
由 eileencodes 提交于
As multiple databases have evolved it's becoming more and more confusing that we have a `connection_specification_name` that defaults to "primary" and a `spec_name` on the database objects that defaults to "primary" (my bad). Even more confusing is that we use the class name for all non-ActiveRecord::Base abstract classes that establish connections. For example connections established on `class MyOtherDatabaseModel < ApplicationRecord` will use `"MyOtherDatabaseModel"` as it's connection specification name while `ActiveRecord::Base` uses `"primary"`. This PR deprecates the use of the name `"primary"` as the `connection_specification_name` for `ActiveRecord::Base` in favor of using `"ActiveRecord::Base"`. In this PR the following is true: * If `handler.establish_connection(:primary)` is called, `"primary"` will not throw a deprecation warning and can still be used for the `connection_specification_name`. This also fixes a bug where using this method to establish a connection could accidentally overwrite the actual `ActiveRecord::Base` connection IF that connection was not using a configuration named `:primary`. * Calling `handler.retrieve_connection "primary"` when `handler.establish_connection :primary` has never been called will return the connection for `ActiveRecord::Base` and throw a deprecation warning. * Calling `handler.remove_connection "primary"` when `handler.establish_connection :primary` has never been called will remove the connection for `ActiveRecord::Base` and throw a deprecation warning. See #38179 for details on more motivations for this change. Co-authored-by: NJohn Crepezzi <john.crepezzi@gmail.com>
-
- 18 12月, 2019 2 次提交
-
-
由 John Crepezzi 提交于
`name` is used by Rails to find the configuration by connection specification name, but database adapters don't need to use `name` in order to establish a connection. This is part of our work to separate what the database needs to connect (the configuration hash) and the what Rails needs to find connections (everything else). Co-authored-by: NJohn Crepezzi <john.crepezzi@gmail.com>
-
由 John Crepezzi 提交于
The `connection_config` method returns a `Hash`, but since we're moving toward a place where we're using `DatabaseConfiguration::DatabaseConfig` objects everywhere, we're introducing a new method here to replace it called `connection_db_config`. Co-authored-by: Neileencodes <eileencodes@gmail.com>
-
- 04 12月, 2019 1 次提交
-
-
由 eileencodes 提交于
The `database` kwarg in `connected_to` has resulted in a lot of bug reports that are trying to use it for sharding when that's not the intent of the key. After considering where the database kwarg is used in tests and thinking about usecases for it, we've determined it should be removed. There are plans to add sharding support and in the mean time the database kwarg isn't the right solution for that. Applications that need to create new connections can use establish_connection or connects_to. Since the database key causes new connections to be established on every call, that causes bugs if connected_to with a database kwarg is used during a request or for any connection that's not a one-off. Co-authored-by: NJohn Crepezzi <john.crepezzi@gmail.com>
-
- 13 11月, 2019 1 次提交
-
-
由 John Crepezzi 提交于
We have these two objects, `ConnectionAdapters::Resolver` and `DatabaseConfiguratons` that implement a lot of the same logic. One of them is used for configurations defined in `config/database.yml` and the other is used when passing raw configurations `String` or `Hash` objects into methods like `establish_connection`. Over time these two have diverged a bit. In the interest of less code complexity, and more consistency for users this commit brings them back together. * Remove `Resolver` altogether and replace its primary method with `DatabaseConfigurations#resolve`. * Move `resolve_pool_config` over to the `ConnectionPool` alongside the code that uses it.
-
- 21 10月, 2019 1 次提交
-
-
由 John Crepezzi 提交于
Rather than return a configuration hash from `resolve_config_for_connection` which also discards the `env_name` and `spec_name`, return a `DatabaseConfig` object! Also make this method private since it's only used inside this class. Co-authored-by: Neileencodes <eileencodes@gmail.com>
-
- 24 9月, 2019 1 次提交
-
-
由 Jean Boussier 提交于
-
- 14 9月, 2019 2 次提交
-
-
由 eileencodes 提交于
Eventually we'd like to get rid of this class altogether but for now this PR reduces the surface area by removing methods from the class and moving classes out into their own files. * `adapter_method` was moved into database configurations * `initialize_dup` was removed because it was only used in tests * Resolver is now it's own class under connection adapters * ConnectionUrlResolver, only used by the configurations, is in a class under DatabaseConfigurations Co-authored-by: NJohn Crepezzi <john.crepezzi@gmail.com>
-
由 John Crepezzi 提交于
This is part 1 of removing the need to pass hashes around inside connection management. This PR creates database config objects every time when passing a hash, string, or symbol and sends that object to connection specification. ConnectionSpecification reaches into the config hash on db_config when needed, but eventually we'll get rid of that and ConnectionSpecification since it's doing duplicate work with the DatabaseConfigurations. We also chose to change the keys to strings because that's what the database.yml would create and what apps currently expect. While symbols are nicer, we'd end up having to deprecate the string behavior first. Co-authored-by: Neileencodes <eileencodes@gmail.com>
-
- 13 9月, 2019 1 次提交
-
-
由 eileencodes 提交于
Previously in some places we used symbol keys, and in some places we used string keys. That made it pretty confusing to figure out in a particular place what type of configuration object you were working with. Now internally, all configuration hashes are keyed by symbols and converted to such on the way in. A few exceptions: - `DatabaseConfigurations#to_h` still returns strings for backward compatibility - Same for `legacy_hash` - `default_hash` previously could return strings, but the associated comment mentions it returns symbol-key `Hash` and now it always does Because this is a change in behavior, a few method renames have happened: - `DatabaseConfig#config` is now `DatabaseConfig#configuration_hash` and returns a symbol-key `Hash` - `ConnectionSpecification#config` is now `ConnectionSpecification#underlying_configuration_hash` and returns the `Hash` of the underlying `DatabaseConfig` - `DatabaseConfig#config` was added back, returns `String`-keys for backward compatibility, and is deprecated in favor of the new `configuration_hash` Co-authored-by: Neileencodes <eileencodes@gmail.com>
-
- 29 8月, 2019 1 次提交
-
-
由 eileencodes 提交于
If a user is using the middleware for swapping database connections and manually calling `connected_to` in a controller/model/etc without calling `while_preventing_writes(false)` there is potential for a race condition where writes will be blocked. While the user could _just_ call `while_preventing_writes` in the same place they call `connected_to` this would mean that all cases need to call two methods. This PR changes `connected_to` to call `while_preventing_writes` directly. By default we'll assume you don't want to prevent writes, but if called with `connected_to(role: :writing, prevent_writes: true)` or from the middleware (which calls `connected_to` this way) the writes will be blocked. For replicas, apps should use readonly users to enforce not writing rather than `while_preventing_writes` directly. Should fix the remaining issues in https://github.com/rails/rails/issues/36830
-
- 14 8月, 2019 1 次提交
-
-
由 Eugene Kenny 提交于
Since 2f8b3972, `ActiveRecord::Base` and `ApplicationRecord` use the same default `connection_specification_name` so that database connections configured on `ApplicationRecord` also apply to `ActiveRecord::Base`. However, when resolving the connection for `ApplicationRecord` we should continue to fall back to `ActiveRecord::Base` when there's no connection explicitly configured, so that setting `connection_specification_name` on `ActiveRecord::Base` affects `ApplicationRecord` and its descendants in this case as it did in previous versions.
-
- 13 6月, 2019 1 次提交
-
-
由 Ryuta Kamizono 提交于
We sometimes say "
✂ ️ newline after `private`" in a code review (e.g. https://github.com/rails/rails/pull/18546#discussion_r23188776, https://github.com/rails/rails/pull/34832#discussion_r244847195). Now `Layout/EmptyLinesAroundAccessModifier` cop have new enforced style `EnforcedStyle: only_before` (https://github.com/rubocop-hq/rubocop/pull/7059). That cop and enforced style will reduce the our code review cost.
-
- 05 6月, 2019 1 次提交
-
-
由 eileencodes 提交于
When someone has a multi-db application their `ApplicationRecord` will look like: ```ruby class ApplicationRecord < ActiveRecord::Base self.abstract_class = true connects_to database: { writing: :primary, reading: :replica } end ``` This will cause us to open 2 connections to ActiveRecord::Base's database when we actually only want 1. This is because Rails sees `ApplicationRecord` and thinks it's a new connection, not the existing `ActiveRecord::Base` connection because the `connection_specification_name` is different. This PR changes `ApplicationRecord` classes to consider themselves the same as the "primary" connection. Fixes #36382
-
- 16 4月, 2019 1 次提交
-
-
由 Sharang Dashputre 提交于
-
- 09 4月, 2019 1 次提交
-
-
由 eileencodes 提交于
After looking at #35800 there is definitely an issue in the `connected_to` method although it's generally behaving. Here are the details: 1) I added a default connection role - writing - to the connection handler lookup. I did this because otherwise if you did this: ``` connected_to(databse: :development) ``` And development wasn't a pre-established role it would create a new handler and connect using that. I don't think this is right so I've updated it to pick up the default (:writing) unless otherwise specified. To set a handler when using the database version pass a hash like you would to `connects_to`: ``` connected_to(database: { readonly_slow: :development }) ``` This will connect the `development` database to the `readonly_slow` handler/role. 2) I updated the tests to match this behavior that we expect. 3) I updated the documentation to clarify that using `connected_to` with a `database` key will establish a new connection every time. This is exactly how `establish_connection` behaves and I feel this is correct. If you want to only establish a connection once you should do that in the model with `connects_to` and then swap on the role instead of on the database hash/key. 4) In regards to #35800 this fixes the case where you pass a symbol to the db and not a hash. But it doesn't fix a case where you may pass an unknown handler to an abstract class that's not connected. This is tricky because technical AbstractFoo doesn't have any connections except for through ApplicationRecord, so in the case of the application that was shared we should only be swapping connections on ActiveRecord::Base because there are no other actual connections - AbstractFoo isn't needed since it's not establishing a new connection. If we need AbstractFoo to connect to a new handler we should establish that connection with the handler in AbstractFoo before trying to shard there.
-
- 02 2月, 2019 1 次提交
-
-
由 Eileen Uchitelle 提交于
This change ensures that all query cahces are cleared across all connections per handler for the current thread so if you write on one connection the read will have the query cache cleared.
-
- 25 1月, 2019 1 次提交
-
-
由 Eileen Uchitelle 提交于
While working on another feature for multiple databases (auto-switching) I observed that in development the first request won't autoload the application record connection for the primary database and may not yet know about the replica connection. In my test application this caused the application to thrown an error if I tried to send the first request to the replica before the replica was connected. This wouldn't be an issue in production because the application is preloaded. In order to fix this I decided to leave the original error message and delete the new error message. I updated the original error message to include the `role` to make it a bit clearer that the connection isn't established for that particular role. The error now reads: ``` No connection pool with 'primary' found for the 'reading' role. ``` A single database application will continue uisng the original error message: ``` No connection pool with 'primary' found. ```
-
- 22 12月, 2018 1 次提交
-
-
由 Eileen Uchitelle 提交于
If you try to call `connected_to` with a role that doesn't have an established connection you used to get an error that said: ``` >> ActiveRecord::Base.connected_to(role: :i_dont_exist) { Home.first } ActiveRecord::ConnectionNotEstablished Exception: No connection pool with 'primary' found. ``` This is confusing because the connection could be established but we spelled the role wrong. I've changed this to raise if the `role` used in `connected_to` doesn't have an associated handler. Users who encounter this should either check that the role is spelled correctly (writin -> writing), establish a connection to that role in the model with connects_to, or use the `database` keyword for the `role`. I think this will provide a less confusing error message for those starting out with multiple databases.
-
- 12 12月, 2018 1 次提交
-
-
由 John Hawthorn 提交于
This can be used to check the currently connected role. It's meant to mirror AR::Base.connected_to
-
- 15 11月, 2018 1 次提交
-
-
由 bogdanvlviv 提交于
Since both methods are public API I think it makes sense to add these tests in order to prevent any regression in the behavior of those methods after the 6.0 release. Exercise `connected_to` - Ensure that the method raises with both `database` and `role` arguments - Ensure that the method raises without `database` and `role` Exercise `connects_to` - Ensure that the method returns an array of established connections(as mentioned in the docs of the method) Related to #34052
-
- 31 10月, 2018 1 次提交
-
-
由 Ryuta Kamizono 提交于
Caused at #34196.
-
- 27 10月, 2018 1 次提交
-
-
由 Gannon McGibbon 提交于
Add support for hash and url configs in database hash of `ActiveRecord::Base.connected_to`.
-
- 11 10月, 2018 1 次提交
-
-
由 Eileen Uchitelle 提交于
This PR adds the ability to 1) connect to multiple databases in a model, and 2) switch between those connections using a block. To connect a model to a set of databases for writing and reading use the following API. This API supercedes `establish_connection`. The `writing` and `reading` keys represent handler / role names and `animals` and `animals_replica` represents the database key to look up the configuration hash from. ``` class AnimalsBase < ApplicationRecord connects_to database: { writing: :animals, reading: :animals_replica } end ``` Inside the application - outside the model declaration - we can switch connections with a block call to `connected_to`. If we want to connect to a db that isn't default (ie readonly_slow) we can connect like this: Outside the model we may want to connect to a new database (one that is not in the default writing/reading set) - for example a slow replica for making slow queries. To do this we have the `connected_to` method that takes a `database` hash that matches the signature of `connects_to`. The `connected_to` method also takes a block. ``` AcitveRecord::Base.connected_to(database: { slow_readonly: :primary_replica_slow }) do ModelInPrimary.do_something_thats_slow end ``` For models that are already loaded and connections that are already connected, `connected_to` doesn't need to pass in a `database` because you may want to run queries against multiple databases using a specific role/handler. In this case `connected_to` can take a `role` and use that to swap on the connection passed. This simplies queries - and matches how we do it in GitHub. Once you're connected to the database you don't need to re-connect, we assume the connection is in the pool and simply pass the handler we'd like to swap on. ``` ActiveRecord::Base.connected_to(role: :reading) do Dog.read_something_from_dog ModelInPrimary.do_something_from_model_in_primary end ```
-
- 30 8月, 2018 1 次提交
-
-
由 Eileen Uchitelle 提交于
While the three-tier config makes it easier to define databases for multiple database applications, it quickly became clear to offer full support for multiple databases we need to change the way the connections hash was handled. A three-tier config means that when Rails needed to choose a default configuration (in the case a user doesn't ask for a specific configuration) it wasn't clear to Rails which the default was. I [bandaid fixed this so the rake tasks could work](#32271) but that fix wasn't correct because it actually doubled up the configuration hashes. Instead of attemping to manipulate the hashes @tenderlove and I decided that it made more sense if we converted the hashes to objects so we can easily ask those object questions. In a three tier config like this: ``` development: primary: database: "my_primary_db" animals: database; "my_animals_db" ``` We end up with an object like this: ``` @configurations=[ #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",@spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>, #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="development",@spec_name="animals", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}> ]> ``` The configurations setter takes the database configuration set by your application and turns them into an `ActiveRecord::DatabaseConfigurations` object that has one getter - `@configurations` which is an array of all the database objects. The configurations getter returns this object by default since it acts like a hash in most of the cases we need. For example if you need to access the default `development` database we can simply request it as we did before: ``` ActiveRecord::Base.configurations["development"] ``` This will return primary development database configuration hash: ``` { "database" => "my_primary_db" } ``` Internally all of Active Record has been converted to use the new objects. I've built this to be backwards compatible but allow for accessing the hash if needed for a deprecation period. To get the original hash instead of the object you can either add `to_h` on the configurations call or pass `legacy: true` to `configurations. ``` ActiveRecord::Base.configurations.to_h => { "development => { "database" => "my_primary_db" } } ActiveRecord::Base.configurations(legacy: true) => { "development => { "database" => "my_primary_db" } } ``` The new configurations object allows us to iterate over the Active Record configurations without losing the known environment or specification name for that configuration. You can also select all the configs for an env or env and spec. With this we can always ask any object what environment it belongs to: ``` db_configs = ActiveRecord::Base.configurations.configurations_for("development") => #<ActiveRecord::DatabaseConfigurations:0x00007fd1acbdf800 @configurations=[ #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbded10 @env_name="development",@spec_name="primary", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}>, #<ActiveRecord::DatabaseConfigurations::HashConfig:0x00007fd1acbdea90 @env_name="development",@spec_name="animals", @config={"adapter"=>"sqlite3", "database"=>"db/development.sqlite3"}> ]> db_config.env_name => "development" db_config.spec_name => "primary" db_config.config => { "adapter"=>"sqlite3", "database"=>"db/development.sqlite3" } ``` The configurations object is more flexible than the configurations hash and will allow us to build on top of the connection management in order to add support for primary/replica connections, sharding, and constructing queries for associations that live in multiple databases.
-
- 17 3月, 2018 1 次提交
-
-
由 eileencodes 提交于
If you had a three-tier config, the `establish_connection` that's called in the Railtie on load can't figure out how to access the default configuration. This is because Rails assumes that the config is the first value in the hash and always associated with the key from the environment. With a three tier config however we need to go one level deeper. This commit includes 2 changes. 1) removes a line from `resolve_all` which was parsing out the the environment from the config so instead of getting ``` { :development => { :primary => { :database => "whatever" } }, :animals => { :database => "whatever-animals" } }, etc with test / prod } ``` We'd instead end up with a config that had no attachment to it's envioronment. ``` { :primary => { :database => "whatever" } :animals => { :database => "whatever-animals" } etc - without test and prod } ``` Not only did this mean that Active Record didn't know how to establish a connection, it didn't have the other necessary configs along with it in the configs list. So fix this I removed the line that deletes these configs. The second thing this commit changes is adding this line to `establish_connection` ``` spec = spec[spec_name.to_sym] if spec[spec_name.to_sym] ``` When you have a three-tier config and don't pass any hash/symbol/env etc to `establish_connection` the resolver will automatically return both the primary and secondary (in this case animals db) configurations. We'll get an `database configuration does not specify adapter` error because AR will try to establish a connection on the `primary` key rather than the `primary` key's config. It assumes that the `development` or default env automatically will return a config hash, but with a three-tier config we actually get a key and config `primary => config`. This fix is a bit of a bandaid because it's not the "correct" way to handle this situation, but it does solve our immediate problem. The new code here is saying "if the config returned from the resolver (I know it's called spec in here but we interchange our meanings a LOT and what is returned is a three-tier config) has a key matching the "primary" spec name, grab the config from the spec and pass that to the estalbish_connection method". This works because if we pass `:animals` or a hash, or `:primary` we'll already have the correct configuration to connect with. This fixes the case where we want Rail to connect with the default connection. Coming soon is a refactoring that should eliminate the need to do this but I need this fix in order to write the multi-db rake tasks that I promised in my RailsConf submission. `@tenderlove` and I are working on the refactoring of the internals for connection management but it won't be ready for a few weeks and this issue has been blocking progress.
-
- 26 11月, 2017 1 次提交
-
-
由 Matthew Draper 提交于
-
- 20 7月, 2017 1 次提交
-
-
由 Kir Shatrov 提交于
-
- 02 7月, 2017 1 次提交
-
-
由 Matthew Draper 提交于
This reverts commit 3420a145, reversing changes made to afb66a5a.
-
- 01 7月, 2017 1 次提交
-
-
由 Kir Shatrov 提交于
-
- 24 5月, 2017 1 次提交
-
-
由 Ryuta Kamizono 提交于
Follow up of #27399.
-
- 02 9月, 2016 1 次提交
-
-
由 Xavier Noria 提交于
-
- 07 8月, 2016 2 次提交
-
-
由 Xavier Noria 提交于
-
由 Xavier Noria 提交于
The current code base is not uniform. After some discussion, we have chosen to go with double quotes by default.
-
- 29 6月, 2016 1 次提交
-
-
由 Sean Griffin 提交于
This method appears to have been partially used in connection pool caching, but it was introduced without much reasoning or any tests. One edge case test was added later on, but it was focused on implementation details. This method is no longer used outside of tests, and as such is removed.
-