Remove most memory related features

I can't maintain anymore this amount of features while keeping the library constantly updated and without bugs. Every merge was taking me multiple hours of revisioning the code. I give up.
From this commit onwards TDLight will only have small useful customizations that are easy to maintain.
Now the people relying on the OptimizeMemory method can restart the session every N hours to free up the memory.
The real way to keep a low memory usage must involve a huge refactoring to allow the unloading of the caches into the sqlite database, similar to what's already happening with messages data. Only Levlam has the ability to implement this without needing to merge the upstream everytime.
This commit is contained in:
Andrea Cavalli 2021-09-25 22:11:42 +02:00
parent 897d4af16c
commit 45e855f89d
70 changed files with 473 additions and 2342 deletions

View File

@ -622,7 +622,7 @@ Changes in 1.5.0 (9 Sep 2019):
* Added the class `chatEventPollStopped` representing the closing of a poll in a message in the chat event log. * Added the class `chatEventPollStopped` representing the closing of a poll in a message in the chat event log.
* Added ability to specify the exact types of problems with a call in the method `sendCallRating` and * Added ability to specify the exact types of problems with a call in the method `sendCallRating` and
the new class `CallProblem`. the new class `CallProblem`.
* Changes in [tdweb](https://github.com/tdlib/td/blob/master/example/web/): * Changes in [tdweb](https://github.com/tdlight-team/tdlight/blob/master/example/web/):
- Supported non-zero `offset` and `limit` in `readFilePart`. - Supported non-zero `offset` and `limit` in `readFilePart`.
----------------------------------------------------------------------------------------------------------------------- -----------------------------------------------------------------------------------------------------------------------
@ -632,7 +632,7 @@ Changes in 1.4.0 (1 May 2019):
* Added a [TDLib build instructions generator](https://tdlib.github.io/td/build.html), covering in details * Added a [TDLib build instructions generator](https://tdlib.github.io/td/build.html), covering in details
TDLib building on the most popular operating systems. TDLib building on the most popular operating systems.
* Added an example of TDLib building and usage from a browser. * Added an example of TDLib building and usage from a browser.
See https://github.com/tdlib/td/blob/master/example/web/ for more details. See https://github.com/tdlight-team/tdlight/blob/master/example/web/ for more details.
* Allowed to pass NULL pointer to `td_json_client_execute` instead of a previously created JSON client. * Allowed to pass NULL pointer to `td_json_client_execute` instead of a previously created JSON client.
Now you can use synchronous TDLib methods through a JSON interface before creating a TDLib JSON client. Now you can use synchronous TDLib methods through a JSON interface before creating a TDLib JSON client.
* Added support for media streaming by allowing to download any part of a file: * Added support for media streaming by allowing to download any part of a file:
@ -883,7 +883,7 @@ Changes in 1.4.0 (1 May 2019):
Changes in 1.3.0 (5 Sep 2018): Changes in 1.3.0 (5 Sep 2018):
* Added a review of existing TDLib based [frameworks](https://github.com/tdlib/td/blob/master/example/README.md) * Added a review of existing TDLib based [frameworks](https://github.com/tdlight-team/tdlight/blob/master/example/README.md)
in different programming languages. in different programming languages.
* Added a [Getting started](https://core.telegram.org/tdlib/getting-started) guide describing the main TDLib concepts * Added a [Getting started](https://core.telegram.org/tdlib/getting-started) guide describing the main TDLib concepts
and basic principles required for library usage. and basic principles required for library usage.

120
README.md
View File

@ -1,82 +1,12 @@
# TDLight # TDLight
TDLight is a fork of tdlib, focused on memory footprint and performance.
TDLight is 100% compatible with tdlib, if you don't use the sqlite database. TDLight is a fork of TDLib, a cross-platform library for building [Telegram](https://telegram.org) clients. It can be easily used from almost any programming language.
⚠️ Memory Cleanup remove nearly every cached value, so you must use it with caution!
This function is not suggested for GUI clients, because they heavily rely on retrieving cached data!
TDLib developers strongly advise against the use of this feature, since it is not an intended behavior.
## Added features
### Memory cleanup
TDLight can clean itself and release some ram to the OS if you want. Look at **TdApi.OptimizeMemory** in "Modified features" paragraph to see how.
### Constant memory usage without restarting
TDLight, if used with care, doesn't grow in memory usage with time. Look at **TdApi.OptimizeMemory** in "Modified features" paragraph to see how
![memory usage](info/memory-usage.jpg)
### Custom options
We added some options:
* **disable_minithumbnails** (true/**false**) This setting removes minithumbnails everywhere. It reduces memory usage because tdlib keeps them in RAM
* **disable_document_filenames** (true/**false**) If you don't care about having the original filenames of every file stored in RAM, you can disable them using this option. It reduces memory usage
* **disable_notifications** (true/**false**) In TDLib pending notification updates are stored in ram until you "read" them. This option disables completely notifications and keeps the pending notifications queue empty, reducing memory usage
* **ignore_update_chat_last_message** (true/**false**) If you don't care about have updateChatLastMessage updates enable this
* **ignore_update_chat_read_inbox** (true/**false**) If you don't care about have updateChatReadInbox updates enable this
* **ignore_update_user_chat_action** (true/**false**) If you don't care about have updateUserChatAction updates enable this
* **ignore_server_deletes_and_reads** (true/**false**) If you don't care about receiving read receipts and remote deletes from other users, enable this, it will reduce memory usage
* **delete_chat_reference_after_seconds** (positive number) During cleanup, free the memory of the chats that have not been touched for more than X seconds
* **delete_user_reference_after_seconds** (positive number) During cleanup, free the memory of the users that have not been touched for more than X seconds
* **delete_file_reference_after_seconds** (positive number) During cleanup, free the memory of the files that have not been touched for more than X seconds
* **receive_access_hashes** (true/**false**) Receive chats and users access hash as updates
* **experiment_enable_file_reference_cleanup** (**true**/false) During cleanup, free the memory of the file references
* **experiment_enable_chat_access_hash_cleanup** (**true**/false) During cleanup, clean chats and channels access hash
* **enable_reactive_channel_difference** (true/**false**) Enable manual `get_channel_difference` execution by calling `getChannelDifference(channel_difference_id)`.
Don't modify this option unless you have a very large bot that struggles to keep up with start-up updates throughput, or you want to use a reactive library.
## Custom API functions
### TdApi.OptimizeMemory
This method is used to optimize the memory usage, but it must be used carefully.
It removes almost all cached values and releases the memory back to the OS.
You can call TdApi.OptimizeMemory normally, but removing cached values
can cause problems if you don't take some precautions.
If you want to avoid receiving data with missing fields during cleanup:
1. Before calling *TdApi.OptimizeMemory* you must:
1. Read all the pending updates to empty the pending updates queue.
2. Disable internet connection using *TdApi.SetNetworkType(TdApi.NetworkTypeNone)*
2. Call *TdApi.OptimizeMemory*
3. After calling *TdApi.OptimizeMemory* you must:
1. **NOT** use the old file ids because they have been deleted! (Example: If you receive the file 12 after OptimizeMemory is not the same file 12 that you received before *TdApi.OptimizeMemory*, because the id 12 has been reused)
2. Re-enable internet connection using *TdApi.SetNetworkType(TdApi.NetworkTypeOther)*
### TdApi.GetMemoryStatistics
This method is used to read the size of all the biggest data maps inside tdlib implementation.
The output contains a string that can be parsed as a JSON.
## Other recommended options
* Options:
* ignore_inline_thumbnails: true
* disable_top_chats: true
* ignore_platform_restrictions: true
* ignore_sensitive_content_restrictions: true
* Disable all the databases (messages_db, users_db, files_db)
⚠️ If you use the databases, TDLight memory cleanup feature will be automatically disabled, because databases will lose some data when cleaning up the memory.
-----
The following text is the classic TDLib readme:
# TDLib
TDLib (Telegram Database library) is a cross-platform library for building [Telegram](https://telegram.org) clients. It can be easily used from almost any programming language.
## Table of Contents ## Table of Contents
- [Features](#features) - [Features](#features)
- [TDLight extra features](#tdlight-extra-features)
- [TDLight extra API functions](#tdlight-extra-api-functions)
- [TDLight recommended options](#tdlight-recommended-options)
- [Examples and documentation](#usage) - [Examples and documentation](#usage)
- [Dependencies](#dependencies) - [Dependencies](#dependencies)
- [Building](#building) - [Building](#building)
@ -101,17 +31,41 @@ TDLib (Telegram Database library) is a cross-platform library for building [Tele
* **Secure**: all local data is encrypted using a user-provided encryption key. * **Secure**: all local data is encrypted using a user-provided encryption key.
* **Fully-asynchronous**: requests to `TDLib` don't block each other or anything else, responses are sent when they are available. * **Fully-asynchronous**: requests to `TDLib` don't block each other or anything else, responses are sent when they are available.
<a name="tdlight-extra-features"></a>
### TDLight extra features
#### TDLight extra options
* **disable_minithumbnails** (true/**false**) This setting removes minithumbnails everywhere. It reduces memory usage because tdlib keeps them in RAM
* **disable_document_filenames** (true/**false**) If you don't care about having the original filenames of every file stored in RAM, you can disable them using this option. It reduces memory usage
* **disable_notifications** (true/**false**) In TDLib pending notification updates are stored in ram until you "read" them. This option disables completely notifications and keeps the pending notifications queue empty, reducing memory usage
* **ignore_update_chat_last_message** (true/**false**) If you don't care about have updateChatLastMessage updates enable this
* **ignore_update_chat_read_inbox** (true/**false**) If you don't care about have updateChatReadInbox updates enable this
* **ignore_update_user_chat_action** (true/**false**) If you don't care about have updateUserChatAction updates enable this
* **ignore_server_deletes_and_reads** (true/**false**) If you don't care about receiving read receipts and remote deletes from other users, enable this, it will reduce memory usage
* **receive_access_hashes** (true/**false**) Receive chats and users access hash as updates
<a name="tdlight-extra-api-functions"></a>
### TDLight extra API functions
#### TdApi.GetMemoryStatistics
This method is used to read the size of all the internal TDLib data structures.
The output contains a string that can be parsed as a JSON.
<a name="tdlight-recommended-options"></a>
## TDLight recommended options
* Options:
* ignore_inline_thumbnails: true
* disable_top_chats: true
* ignore_platform_restrictions: true
* ignore_sensitive_content_restrictions: true
* Disable all the databases (messages_db, users_db, files_db)
<a name="usage"></a> <a name="usage"></a>
## Examples and documentation ## Examples and documentation
See our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts. See our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts.
Take a look at our [examples](https://github.com/tdlib/td/blob/master/example/README.md#tdlib-usage-and-build-examples). Take a look at our [examples](https://github.com/tdlight-team/tdlight/blob/master/example/README.md#tdlib-usage-and-build-examples).
See a [TDLight build instructions generator](https://tdlight-team.github.io/tdlight/build.html) for detailed instructions on how to build TDLib. See a [TDLight build instructions generator](https://tdlight-team.github.io/tdlight/build.html) for detailed instructions on how to build TDLib.
See description of our [JSON](#using-json), [C++](#using-cxx), [Java](#using-java) and [.NET](#using-dotnet) interfaces. See description of our [JSON](#using-json), [C++](#using-cxx), [Java](#using-java) and [.NET](#using-dotnet) interfaces.
See the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) See the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html)
for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html). for a list of all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
<a name="dependencies"></a> <a name="dependencies"></a>
@ -140,7 +94,7 @@ cmake -DCMAKE_BUILD_TYPE=Release ..
cmake --build . cmake --build .
``` ```
To build `TDLib` on low memory devices you can run [SplitSource.php](https://github.com/tdlib/td/blob/master/SplitSource.php) script To build `TDLib` on low memory devices you can run [SplitSource.php](https://github.com/tdlight-team/tdlight/blob/master/SplitSource.php) script
before compiling main `TDLib` source code and compile only needed targets: before compiling main `TDLib` source code and compile only needed targets:
``` ```
mkdir build mkdir build
@ -179,21 +133,21 @@ Or you could install `TDLib` and then reference it in your CMakeLists.txt like t
find_package(Td 1.7.8 REQUIRED) find_package(Td 1.7.8 REQUIRED)
target_link_libraries(YourTarget PRIVATE Td::TdStatic) target_link_libraries(YourTarget PRIVATE Td::TdStatic)
``` ```
See [example/cpp/CMakeLists.txt](https://github.com/tdlib/td/tree/master/example/cpp/CMakeLists.txt). See [example/cpp/CMakeLists.txt](https://github.com/tdlight-team/tdlight/tree/master/example/cpp/CMakeLists.txt).
<a name="using-java"></a> <a name="using-java"></a>
## Using in Java projects ## Using in Java projects
`TDLib` provides native Java interface through JNI. To enable it, specify option `-DTD_ENABLE_JNI=ON` to CMake. `TDLib` provides native Java interface through JNI. To enable it, specify option `-DTD_ENABLE_JNI=ON` to CMake.
See [example/java](https://github.com/tdlib/td/tree/master/example/java) for example of using `TDLib` from Java and detailed build and usage instructions. See [example/java](https://github.com/tdlight-team/tdlight/tree/master/example/java) for example of using `TDLib` from Java and detailed build and usage instructions.
<a name="using-dotnet"></a> <a name="using-dotnet"></a>
## Using in .NET projects ## Using in .NET projects
`TDLib` provides native .NET interface through `C++/CLI` and `C++/CX`. To enable it, specify option `-DTD_ENABLE_DOTNET=ON` to CMake. `TDLib` provides native .NET interface through `C++/CLI` and `C++/CX`. To enable it, specify option `-DTD_ENABLE_DOTNET=ON` to CMake.
.NET Core supports `C++/CLI` only since version 3.1 and only on Windows, so if older .NET Core is used or portability is needed, then `TDLib` JSON interface should be used through P/Invoke instead. .NET Core supports `C++/CLI` only since version 3.1 and only on Windows, so if older .NET Core is used or portability is needed, then `TDLib` JSON interface should be used through P/Invoke instead.
See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions. See [example/csharp](https://github.com/tdlight-team/tdlight/tree/master/example/csharp) for example of using `TDLib` from C# and detailed build and usage instructions.
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform". See [example/uwp](https://github.com/tdlight-team/tdlight/tree/master/example/uwp) for example of using `TDLib` from C# UWP application and detailed build and usage instructions for Visual Studio Extension "TDLib for Universal Windows Platform".
When `TDLib` is built with `TD_ENABLE_DOTNET` option enabled, `C++` documentation is removed from some files. You need to checkout these files to return `C++` documentation back: When `TDLib` is built with `TD_ENABLE_DOTNET` option enabled, `C++` documentation is removed from some files. You need to checkout these files to return `C++` documentation back:
``` ```
@ -205,13 +159,13 @@ git checkout td/telegram/Client.h td/telegram/Log.h td/tl/TlObject.h
`TDLib` provides efficient native C++, Java, and .NET interfaces. `TDLib` provides efficient native C++, Java, and .NET interfaces.
But for most use cases we suggest to use the JSON interface, which can be easily used with any programming language that is able to execute C functions. But for most use cases we suggest to use the JSON interface, which can be easily used with any programming language that is able to execute C functions.
See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) documentation for detailed JSON interface description, See [td_json_client](https://core.telegram.org/tdlib/docs/td__json__client_8h.html) documentation for detailed JSON interface description,
the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of
all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html). all available `TDLib` [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
`TDLib` JSON interface adheres to semantic versioning and versions with the same major version number are binary and backward compatible, but the underlying `TDLib` API can be different for different minor and even patch versions. `TDLib` JSON interface adheres to semantic versioning and versions with the same major version number are binary and backward compatible, but the underlying `TDLib` API can be different for different minor and even patch versions.
If you need to support different `TDLib` versions, then you can use a value of the `version` option to find exact `TDLib` version to use appropriate API methods. If you need to support different `TDLib` versions, then you can use a value of the `version` option to find exact `TDLib` version to use appropriate API methods.
See [example/python/tdjson_example.py](https://github.com/tdlib/td/tree/master/example/python/tdjson_example.py) for an example of such usage. See [example/python/tdjson_example.py](https://github.com/tdlight-team/tdlight/tree/master/example/python/tdjson_example.py) for an example of such usage.
<a name="license"></a> <a name="license"></a>
## License ## License

View File

@ -544,7 +544,7 @@ function onOptionsChanged() {
} }
if (os_mac) { if (os_mac) {
pre_text.push('Note that the following instruction will build TDLib only for the current architecture (x64 or Apple silicon).'); pre_text.push('Note that the following instruction will build TDLib only for the current architecture (x64 or Apple silicon).');
pre_text.push('If you want to create a universal XCFramework, take a look at our <a href="https://github.com/tdlib/td/tree/master/example/ios">example</a> instead.'); pre_text.push('If you want to create a universal XCFramework, take a look at our <a href="https://github.com/tdlight-team/tdlight/tree/master/example/ios">example</a> instead.');
} }
var terminal_name = (function () { var terminal_name = (function () {

View File

@ -1,7 +1,7 @@
# TDLib usage and build examples # TDLib usage and build examples
This directory contains basic examples of TDLib usage from different programming languages and examples of library building for different platforms. This directory contains basic examples of TDLib usage from different programming languages and examples of library building for different platforms.
If you are looking for documentation of all available TDLib methods, see the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or the If you are looking for documentation of all available TDLib methods, see the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or the
automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available TDLib automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available TDLib
[methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html). [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
Also take a look at our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts. Also take a look at our [Getting Started](https://core.telegram.org/tdlib/getting-started) tutorial for a description of basic TDLib concepts.
@ -53,13 +53,13 @@ This wrapper contains automatically generated fully-documented classes for all T
For older Python versions you can use [pytdlib](https://github.com/pytdlib/pytdlib). For older Python versions you can use [pytdlib](https://github.com/pytdlib/pytdlib).
This wrapper contains generator for TDLib API classes and basic interface for interaction with TDLib. This wrapper contains generator for TDLib API classes and basic interface for interaction with TDLib.
You can also check out [example/python/tdjson_example.py](https://github.com/tdlib/td/tree/master/example/python/tdjson_example.py) and You can also check out [example/python/tdjson_example.py](https://github.com/tdlight-team/tdlight/tree/master/example/python/tdjson_example.py) and
[tdlib-python](https://github.com/JunaidBabu/tdlib-python) for some very basic examples of TDLib JSON interface integration with Python. [tdlib-python](https://github.com/JunaidBabu/tdlib-python) for some very basic examples of TDLib JSON interface integration with Python.
<a name="javascript"></a> <a name="javascript"></a>
## Using TDLib in JavaScript projects ## Using TDLib in JavaScript projects
TDLib can be compiled to WebAssembly or asm.js and used in a browser from JavaScript. See [tdweb](https://github.com/tdlib/td/tree/master/example/web) as a convenient wrapper for TDLib in a browser TDLib can be compiled to WebAssembly or asm.js and used in a browser from JavaScript. See [tdweb](https://github.com/tdlight-team/tdlight/tree/master/example/web) as a convenient wrapper for TDLib in a browser
and [telegram-react](https://github.com/evgeny-nadymov/telegram-react) as an example of a TDLib-based Telegram client. and [telegram-react](https://github.com/evgeny-nadymov/telegram-react) as an example of a TDLib-based Telegram client.
TDLib can be used from Node.js through the [JSON](https://github.com/tdlib/td#using-json) interface. TDLib can be used from Node.js through the [JSON](https://github.com/tdlib/td#using-json) interface.
@ -90,7 +90,7 @@ You can also see [go-tdjson](https://github.com/L11R/go-tdjson) for another exam
TDLib can be used from the Java programming language through native [JNI](https://github.com/tdlib/td#using-java) binding. TDLib can be used from the Java programming language through native [JNI](https://github.com/tdlib/td#using-java) binding.
We provide a generator for JNI bridge methods and Java classes for all TDLib API methods and objects. We provide a generator for JNI bridge methods and Java classes for all TDLib API methods and objects.
See [example/java](https://github.com/tdlib/td/tree/master/example/java) for an example of using TDLib from desktop Java along with detailed building and usage instructions. See [example/java](https://github.com/tdlight-team/tdlight/tree/master/example/java) for an example of using TDLib from desktop Java along with detailed building and usage instructions.
To use TDLib to create Android Java applications, use our [prebuilt library for Android](https://core.telegram.org/tdlib/tdlib.zip). To use TDLib to create Android Java applications, use our [prebuilt library for Android](https://core.telegram.org/tdlib/tdlib.zip).
You can also see [JTDLib](https://github.com/ErnyTech/JTDLib) for another example of Java wrapper for TDLib. You can also see [JTDLib](https://github.com/ErnyTech/JTDLib) for another example of Java wrapper for TDLib.
@ -110,8 +110,8 @@ See also [KtLib](https://github.com/nekohasekai/KtLib), which provides an automa
TDLib provides a native [.NET](https://github.com/tdlib/td#using-dotnet) interface through `C++/CLI` and `C++/CX`. TDLib provides a native [.NET](https://github.com/tdlib/td#using-dotnet) interface through `C++/CLI` and `C++/CX`.
See [tdlib-netcore](https://github.com/dantmnf/tdlib-netcore) for a SWIG-like binding with automatically generated classes for TDLib API. See [tdlib-netcore](https://github.com/dantmnf/tdlib-netcore) for a SWIG-like binding with automatically generated classes for TDLib API.
See [example/uwp](https://github.com/tdlib/td/tree/master/example/uwp) for an example of building TDLib SDK for the Universal Windows Platform and an example of its usage from C#. See [example/uwp](https://github.com/tdlight-team/tdlight/tree/master/example/uwp) for an example of building TDLib SDK for the Universal Windows Platform and an example of its usage from C#.
See [example/csharp](https://github.com/tdlib/td/tree/master/example/csharp) for an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C# on Windows. See [example/csharp](https://github.com/tdlight-team/tdlight/tree/master/example/csharp) for an example of building TDLib with `C++/CLI` support and an example of TDLib usage from C# on Windows.
If you want to write a cross-platform C# application using .NET Core, see [tdsharp](https://github.com/egramtel/tdsharp). It uses our [JSON](https://github.com/tdlib/td#using-json) interface, If you want to write a cross-platform C# application using .NET Core, see [tdsharp](https://github.com/egramtel/tdsharp). It uses our [JSON](https://github.com/tdlib/td#using-json) interface,
provides an asynchronous interface for interaction with TDLib, automatically generated classes for TDLib API and has some examples. provides an asynchronous interface for interaction with TDLib, automatically generated classes for TDLib API and has some examples.
@ -125,8 +125,8 @@ Also see [Unigram](https://github.com/UnigramDev/Unigram), which is a full-featu
TDLib has a simple and convenient C++11-interface for sending and receiving requests and can be statically linked to your application. TDLib has a simple and convenient C++11-interface for sending and receiving requests and can be statically linked to your application.
See [example/cpp](https://github.com/tdlib/td/tree/master/example/cpp) for an example of TDLib usage from C++. See [example/cpp](https://github.com/tdlight-team/tdlight/tree/master/example/cpp) for an example of TDLib usage from C++.
[td_example.cpp](https://github.com/tdlib/td/tree/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message. [td_example.cpp](https://github.com/tdlight-team/tdlight/tree/master/example/cpp/td_example.cpp) contains an example of authorization, processing new incoming messages, getting a list of chats and sending a text message.
See also the source code of [Fernschreiber](https://github.com/Wunderfitz/harbour-fernschreiber) and [Depecher](https://github.com/blacksailer/depecher) Telegram apps for Sailfish OS, See also the source code of [Fernschreiber](https://github.com/Wunderfitz/harbour-fernschreiber) and [Depecher](https://github.com/blacksailer/depecher) Telegram apps for Sailfish OS,
[TELEports](https://gitlab.com/ubports/apps/teleports) a Qt-client for Ubuntu Touch, or [tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin, all of which are based on TDLib. [TELEports](https://gitlab.com/ubports/apps/teleports) a Qt-client for Ubuntu Touch, or [tdlib-purple](https://github.com/ars3niy/tdlib-purple) - Telegram plugin for Pidgin, all of which are based on TDLib.
@ -136,18 +136,18 @@ See also the source code of [Fernschreiber](https://github.com/Wunderfitz/harbou
TDLib can be used from the Swift programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically. TDLib can be used from the Swift programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS. See [example/ios](https://github.com/tdlight-team/tdlight/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
See [TDLibKit](https://github.com/Swiftgram/TDLibKit), [tdlib-swift](https://github.com/modestman/tdlib-swift), or [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects. See [TDLibKit](https://github.com/Swiftgram/TDLibKit), [tdlib-swift](https://github.com/modestman/tdlib-swift), or [TDLib-iOS](https://github.com/leoMehlig/TDLib-iOS), which provide convenient TDLib clients with automatically generated and fully-documented classes for all TDLib API methods and objects.
See [example/swift](https://github.com/tdlib/td/tree/master/example/swift) for an example of a macOS Swift application. See [example/swift](https://github.com/tdlight-team/tdlight/tree/master/example/swift) for an example of a macOS Swift application.
<a name="objective-c"></a> <a name="objective-c"></a>
## Using TDLib in Objective-C projects ## Using TDLib in Objective-C projects
TDLib can be used from the Objective-C programming language through [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically. TDLib can be used from the Objective-C programming language through [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
See [example/ios](https://github.com/tdlib/td/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS. See [example/ios](https://github.com/tdlight-team/tdlight/tree/master/example/ios) for an example of building TDLib for iOS, watchOS, tvOS, and macOS.
<a name="object-pascal"></a> <a name="object-pascal"></a>
## Using TDLib in Object Pascal projects with Delphi and Lazarus ## Using TDLib in Object Pascal projects with Delphi and Lazarus
@ -163,7 +163,7 @@ See [tdlib-lazarus](https://github.com/dieletro/tdlib-lazarus) for an example of
TDLib can be used from the Dart programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and a Dart Native Extension or Dart FFI. TDLib can be used from the Dart programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and a Dart Native Extension or Dart FFI.
See [dart_tdlib](https://github.com/periodicaidan/dart_tdlib) or [Dart wrapper for TDLib](https://github.com/tdlib/td/pull/708/commits/237060abd4c205768153180e9f814298d1aa9d49) for an example of a TDLib Dart bindings through FFI. See [dart_tdlib](https://github.com/periodicaidan/dart_tdlib) or [Dart wrapper for TDLib](https://github.com/tdlight-team/tdlight/pull/708/commits/237060abd4c205768153180e9f814298d1aa9d49) for an example of a TDLib Dart bindings through FFI.
See [project.scarlet](https://github.com/aaugmentum/project.scarlet), [tdlib](https://github.com/i-Naji/tdlib), [tdlib](https://github.com/pqhaz/tdlib), See [project.scarlet](https://github.com/aaugmentum/project.scarlet), [tdlib](https://github.com/i-Naji/tdlib), [tdlib](https://github.com/pqhaz/tdlib),
[tdlib-dart](https://github.com/drewpayment/tdlib-dart), [tdlib-dart](https://github.com/triedcatched/tdlib-dart), or [telegram-service](https://github.com/igorder-dev/telegram-service) for examples of using TDLib from Dart. [tdlib-dart](https://github.com/drewpayment/tdlib-dart), [tdlib-dart](https://github.com/triedcatched/tdlib-dart), or [telegram-service](https://github.com/igorder-dev/telegram-service) for examples of using TDLib from Dart.
@ -282,7 +282,7 @@ See [TDLib bindings for 1С:Enterprise](https://github.com/Infactum/telegram-nat
TDLib can be used from the C programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically. TDLib can be used from the C programming language through the [JSON](https://github.com/tdlib/td#using-json) interface and can be linked statically or dynamically.
You can also try to use our [C](https://github.com/tdlib/td/blob/master/td/telegram/td_c_client.h) client, which was used by the private TDLib-based version of [telegram-cli](https://github.com/vysheng/tg). You can also try to use our [C](https://github.com/tdlight-team/tdlight/blob/master/td/telegram/td_c_client.h) client, which was used by the private TDLib-based version of [telegram-cli](https://github.com/vysheng/tg).
<a name="other"></a> <a name="other"></a>
## Using TDLib from other programming languages ## Using TDLib from other programming languages

View File

@ -4,7 +4,7 @@ Below are instructions for building TDLib for iOS, watchOS, tvOS, and also macOS
If you need only a macOS build for the current architecture, take a look at [TDLib build instructions generator](https://tdlib.github.io/td/build.html). If you need only a macOS build for the current architecture, take a look at [TDLib build instructions generator](https://tdlib.github.io/td/build.html).
For example of usage take a look at our [Swift example](https://github.com/tdlib/td/tree/master/example/swift). For example of usage take a look at our [Swift example](https://github.com/tdlight-team/tdlight/tree/master/example/swift).
To compile `TDLib` you will need to: To compile `TDLib` you will need to:
* Install the latest Xcode via `xcode-select --install` or downloading it from [Xcode website](https://developer.apple.com/xcode/). * Install the latest Xcode via `xcode-select --install` or downloading it from [Xcode website](https://developer.apple.com/xcode/).
@ -37,7 +37,7 @@ cd <path to TDLib sources>/example/ios
``` ```
This may take a while, because TDLib will be built about 16 times. This may take a while, because TDLib will be built about 16 times.
Resulting XCFramework will work on any architecture and even on a simulator (x64, Apple silicon). Resulting XCFramework will work on any architecture and even on a simulator (x64, Apple silicon).
We use [CMake/iOS.cmake](https://github.com/tdlib/td/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too. We use [CMake/iOS.cmake](https://github.com/tdlight-team/tdlight/blob/master/CMake/iOS.cmake) toolchain, other toolchains may work too.
Built libraries and XCFramework will be stored in `tdjson` directory. Built libraries and XCFramework will be stored in `tdjson` directory.

View File

@ -6,7 +6,7 @@
<MoreInfo>https://core.telegram.org/tdlib</MoreInfo> <MoreInfo>https://core.telegram.org/tdlib</MoreInfo>
<Tags>Telegram, TDLib, library, client, API</Tags> <Tags>Telegram, TDLib, library, client, API</Tags>
<License>LICENSE_1_0.txt</License> <License>LICENSE_1_0.txt</License>
<ReleaseNotes>https://github.com/tdlib/td/blob/master/CHANGELOG.md</ReleaseNotes> <ReleaseNotes>https://github.com/tdlight-team/tdlight/blob/master/CHANGELOG.md</ReleaseNotes>
</Metadata> </Metadata>
<Installation Scope="Global"> <Installation Scope="Global">
<InstallationTarget Id="Microsoft.ExtensionSDK" TargetPlatformIdentifier="UAP" TargetPlatformVersion="v0.8.0.0" SdkName="Telegram.Td.UWP" SdkVersion="1.0" /> <InstallationTarget Id="Microsoft.ExtensionSDK" TargetPlatformIdentifier="UAP" TargetPlatformVersion="v0.8.0.0" SdkName="Telegram.Td.UWP" SdkVersion="1.0" />

View File

@ -26,4 +26,4 @@ cd <path to TDLib sources>/example/web
## Using tdweb NPM package ## Using tdweb NPM package
See [tdweb](https://www.npmjs.com/package/tdweb) or [README.md](https://github.com/tdlib/td/tree/master/example/web/tdweb/README.md) for package documentation. See [tdweb](https://www.npmjs.com/package/tdweb) or [README.md](https://github.com/tdlight-team/tdlight/tree/master/example/web/tdweb/README.md) for package documentation.

View File

@ -8,11 +8,11 @@ Once this is done, you can send queries to the TDLib instance using the method `
See [Getting Started](https://core.telegram.org/tdlib/getting-started) for a description of basic TDLib concepts and a short introduction to TDLib usage. See [Getting Started](https://core.telegram.org/tdlib/getting-started) for a description of basic TDLib concepts and a short introduction to TDLib usage.
See the [td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme or See the [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme or
the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available the automatically generated [HTML documentation](https://core.telegram.org/tdlib/docs/td__api_8h.html) for a list of all available
TDLib [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html). TDLib [methods](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html) and [classes](https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html).
The JSON representation of TDLib API objects is straightforward: all API objects are represented as JSON objects with the same keys as the API object field names in the The JSON representation of TDLib API objects is straightforward: all API objects are represented as JSON objects with the same keys as the API object field names in the
[td_api.tl](https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore [td_api.tl](https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl) scheme. Note that in the automatically generated C++ documentation all fields have an additional terminating underscore
which shouldn't be used in the JSON interface. The object type name is stored in the special field '@type' which is optional in places where type is uniquely determined by the context. which shouldn't be used in the JSON interface. The object type name is stored in the special field '@type' which is optional in places where type is uniquely determined by the context.
Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of int64 and string types are stored as String, Fields of Bool type are stored as Boolean, fields of int32, int53, and double types are stored as Number, fields of int64 and string types are stored as String,
fields of bytes type are base64 encoded and then stored as String, fields of array type are stored as Array. fields of bytes type are base64 encoded and then stored as String, fields of array type are stored as Array.

View File

@ -65,7 +65,7 @@ class TdClient {
* *
* If the query contains the field '@extra', the same field will be added into the result. * If the query contains the field '@extra', the same field will be added into the result.
* *
* @param {Object} query - The query for TDLib. See the [td_api.tl]{@link https://github.com/tdlib/td/blob/master/td/generate/scheme/td_api.tl} scheme or * @param {Object} query - The query for TDLib. See the [td_api.tl]{@link https://github.com/tdlight-team/tdlight/blob/master/td/generate/scheme/td_api.tl} scheme or
* the automatically generated [HTML documentation]{@link https://core.telegram.org/tdlib/docs/td__api_8h.html} * the automatically generated [HTML documentation]{@link https://core.telegram.org/tdlib/docs/td__api_8h.html}
* for a list of all available TDLib [methods]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html} and * for a list of all available TDLib [methods]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_function.html} and
* [classes]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html}. * [classes]{@link https://core.telegram.org/tdlib/docs/classtd_1_1td__api_1_1_object.html}.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 173 KiB

View File

@ -1,24 +0,0 @@
# Manual checks
## After every merge
1. Find if any `get_channel_difference` has been added to `MessagesManager.cpp`, and replace it with `delayed_get_channel_difference`.
### Example
The following line
```cpp
get_channel_difference(dialog_id, old_pts, true, "add_pending_channel_update pts mismatch");
```
should become
```cpp
auto enable_reactive_channel_difference
= G()->shared_config()
.get_option_boolean("enable_reactive_channel_difference", false);
get_channel_difference_delayed(dialog_id, old_pts, true,
enable_reactive_channel_difference,
"add_pending_channel_update pts mismatch");
```
2. Find `make_unique<Dialog>` and check if there's `d.set_time()` after.

View File

@ -5408,10 +5408,6 @@ getDatabaseStatistics = DatabaseStatistics;
//@full Full memory statistics calculation //@full Full memory statistics calculation
getMemoryStatistics full:Bool = MemoryStatistics; getMemoryStatistics full:Bool = MemoryStatistics;
//@description Optimize memory
//@full Full memory optimization
optimizeMemory full:Bool = Ok;
//@description Optimizes storage usage, i.e. deletes some files and returns new storage usage statistics. Secret thumbnails can't be deleted //@description Optimizes storage usage, i.e. deletes some files and returns new storage usage statistics. Secret thumbnails can't be deleted
//@size Limit on the total size of files after deletion, in bytes. Pass -1 to use the default limit //@size Limit on the total size of files after deletion, in bytes. Pass -1 to use the default limit
//@ttl Limit on the time that has passed since the last time a file was accessed (or creation time for some filesystems). Pass -1 to use the default limit //@ttl Limit on the time that has passed since the last time a file was accessed (or creation time for some filesystems). Pass -1 to use the default limit

View File

@ -80,9 +80,7 @@ class SaveGifQuery final : public Td::ResultHandler {
} }
void send(FileId file_id, tl_object_ptr<telegram_api::inputDocument> &&input_document, bool unsave) { void send(FileId file_id, tl_object_ptr<telegram_api::inputDocument> &&input_document, bool unsave) {
if (input_document == nullptr) { CHECK(input_document != nullptr);
return;
}
CHECK(file_id.is_valid()); CHECK(file_id.is_valid());
file_id_ = file_id; file_id_ = file_id;
file_reference_ = input_document->file_reference_.as_slice().str(); file_reference_ = input_document->file_reference_.as_slice().str();
@ -146,17 +144,11 @@ AnimationsManager::AnimationsManager(Td *td, ActorShared<> parent) : td_(td), pa
void AnimationsManager::tear_down() { void AnimationsManager::tear_down() {
parent_.reset(); parent_.reset();
if (td_->memory_manager_->can_manage_memory()) {
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup(true);
}
} }
int32 AnimationsManager::get_animation_duration(FileId file_id) const { int32 AnimationsManager::get_animation_duration(FileId file_id) const {
auto it = animations_.find(file_id); auto it = animations_.find(file_id);
if (it == animations_.end() || it->second == nullptr) { CHECK(it != animations_.end());
return 0;
}
return it->second->duration; return it->second->duration;
} }
@ -166,13 +158,9 @@ tl_object_ptr<td_api::animation> AnimationsManager::get_animation_object(FileId
} }
auto it = animations_.find(file_id); auto it = animations_.find(file_id);
if (it == animations_.end()) { CHECK(it != animations_.end());
return nullptr;
}
auto animation = it->second.get(); auto animation = it->second.get();
if (animation == nullptr) { CHECK(animation != nullptr);
return nullptr;
}
auto thumbnail = auto thumbnail =
animation->animated_thumbnail.file_id.is_valid() animation->animated_thumbnail.file_id.is_valid()
? get_thumbnail_object(td_->file_manager_.get(), animation->animated_thumbnail, PhotoFormat::Mpeg4) ? get_thumbnail_object(td_->file_manager_.get(), animation->animated_thumbnail, PhotoFormat::Mpeg4)
@ -245,8 +233,8 @@ FileId AnimationsManager::on_get_animation(unique_ptr<Animation> new_animation,
const AnimationsManager::Animation *AnimationsManager::get_animation(FileId file_id) const { const AnimationsManager::Animation *AnimationsManager::get_animation(FileId file_id) const {
auto animation = animations_.find(file_id); auto animation = animations_.find(file_id);
if (animation == animations_.end() || animation->second == nullptr) { if (animation == animations_.end()) {
return make_unique<Animation>().get(); return nullptr;
} }
CHECK(animation->second->file_id == file_id); CHECK(animation->second->file_id == file_id);
@ -255,25 +243,19 @@ const AnimationsManager::Animation *AnimationsManager::get_animation(FileId file
FileId AnimationsManager::get_animation_thumbnail_file_id(FileId file_id) const { FileId AnimationsManager::get_animation_thumbnail_file_id(FileId file_id) const {
auto animation = get_animation(file_id); auto animation = get_animation(file_id);
if (animation == nullptr) { CHECK(animation != nullptr);
return FileId();
}
return animation->thumbnail.file_id; return animation->thumbnail.file_id;
} }
FileId AnimationsManager::get_animation_animated_thumbnail_file_id(FileId file_id) const { FileId AnimationsManager::get_animation_animated_thumbnail_file_id(FileId file_id) const {
auto animation = get_animation(file_id); auto animation = get_animation(file_id);
if (animation == nullptr) { CHECK(animation != nullptr);
return FileId();
}
return animation->animated_thumbnail.file_id; return animation->animated_thumbnail.file_id;
} }
void AnimationsManager::delete_animation_thumbnail(FileId file_id) { void AnimationsManager::delete_animation_thumbnail(FileId file_id) {
auto &animation = animations_[file_id]; auto &animation = animations_[file_id];
if (animation == nullptr) { CHECK(animation != nullptr);
return;
}
animation->thumbnail = PhotoSize(); animation->thumbnail = PhotoSize();
animation->animated_thumbnail = AnimationSize(); animation->animated_thumbnail = AnimationSize();
} }
@ -302,7 +284,7 @@ void AnimationsManager::merge_animations(FileId new_id, FileId old_id, bool can_
bool need_merge = true; bool need_merge = true;
auto new_it = animations_.find(new_id); auto new_it = animations_.find(new_id);
if (new_it == animations_.end() || new_it->second == nullptr) { if (new_it == animations_.end()) {
auto &old = animations_[old_id]; auto &old = animations_[old_id];
if (!can_delete_old) { if (!can_delete_old) {
dup_animation(new_id, old_id); dup_animation(new_id, old_id);
@ -368,9 +350,7 @@ tl_object_ptr<telegram_api::InputMedia> AnimationsManager::get_input_media(
if (input_file != nullptr) { if (input_file != nullptr) {
const Animation *animation = get_animation(file_id); const Animation *animation = get_animation(file_id);
if (animation == nullptr) { CHECK(animation != nullptr);
return nullptr;
}
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes; vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
if (!animation->file_name.empty()) { if (!animation->file_name.empty()) {
@ -411,9 +391,7 @@ SecretInputMedia AnimationsManager::get_secret_input_media(FileId animation_file
tl_object_ptr<telegram_api::InputEncryptedFile> input_file, tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
const string &caption, BufferSlice thumbnail) const { const string &caption, BufferSlice thumbnail) const {
auto *animation = get_animation(animation_file_id); auto *animation = get_animation(animation_file_id);
if (animation == nullptr) { CHECK(animation != nullptr);
return SecretInputMedia{};
}
auto file_view = td_->file_manager_->get_file_view(animation_file_id); auto file_view = td_->file_manager_->get_file_view(animation_file_id);
auto &encryption_key = file_view.encryption_key(); auto &encryption_key = file_view.encryption_key();
if (!file_view.is_encrypted_secret() || encryption_key.empty()) { if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
@ -697,9 +675,7 @@ int64 AnimationsManager::get_saved_animations_hash(const char *source) const {
numbers.reserve(saved_animation_ids_.size()); numbers.reserve(saved_animation_ids_.size());
for (auto animation_id : saved_animation_ids_) { for (auto animation_id : saved_animation_ids_) {
auto animation = get_animation(animation_id); auto animation = get_animation(animation_id);
if (animation == nullptr) { CHECK(animation != nullptr);
continue;
}
auto file_view = td_->file_manager_->get_file_view(animation_id); auto file_view = td_->file_manager_->get_file_view(animation_id);
CHECK(file_view.has_remote_location()); CHECK(file_view.has_remote_location());
if (!file_view.remote_location().is_document()) { if (!file_view.remote_location().is_document()) {
@ -742,9 +718,6 @@ void AnimationsManager::send_save_gif_query(FileId animation_id, bool unsave, Pr
void AnimationsManager::add_saved_animation_by_id(FileId animation_id) { void AnimationsManager::add_saved_animation_by_id(FileId animation_id) {
auto animation = get_animation(animation_id); auto animation = get_animation(animation_id);
if (animation == nullptr) {
return;
}
CHECK(animation != nullptr); CHECK(animation != nullptr);
if (animation->has_stickers) { if (animation->has_stickers) {
return; return;
@ -883,7 +856,6 @@ void AnimationsManager::send_update_saved_animations(bool from_database) {
vector<FileId> new_saved_animation_file_ids = saved_animation_ids_; vector<FileId> new_saved_animation_file_ids = saved_animation_ids_;
for (auto &animation_id : saved_animation_ids_) { for (auto &animation_id : saved_animation_ids_) {
auto animation = get_animation(animation_id); auto animation = get_animation(animation_id);
if (animation != nullptr) {
CHECK(animation != nullptr); CHECK(animation != nullptr);
if (animation->thumbnail.file_id.is_valid()) { if (animation->thumbnail.file_id.is_valid()) {
new_saved_animation_file_ids.push_back(animation->thumbnail.file_id); new_saved_animation_file_ids.push_back(animation->thumbnail.file_id);
@ -892,7 +864,6 @@ void AnimationsManager::send_update_saved_animations(bool from_database) {
new_saved_animation_file_ids.push_back(animation->animated_thumbnail.file_id); new_saved_animation_file_ids.push_back(animation->animated_thumbnail.file_id);
} }
} }
}
std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end()); std::sort(new_saved_animation_file_ids.begin(), new_saved_animation_file_ids.end());
if (new_saved_animation_file_ids != saved_animation_file_ids_) { if (new_saved_animation_file_ids != saved_animation_file_ids_) {
td_->file_manager_->change_files_source(get_saved_animations_file_source_id(), saved_animation_file_ids_, td_->file_manager_->change_files_source(get_saved_animations_file_source_id(), saved_animation_file_ids_,
@ -925,9 +896,7 @@ FileSourceId AnimationsManager::get_saved_animations_file_source_id() {
string AnimationsManager::get_animation_search_text(FileId file_id) const { string AnimationsManager::get_animation_search_text(FileId file_id) const {
auto animation = get_animation(file_id); auto animation = get_animation(file_id);
if (animation == nullptr) { CHECK(animation != nullptr);
return "";
}
return animation->file_name; return animation->file_name;
} }
@ -951,17 +920,6 @@ void AnimationsManager::get_current_state(vector<td_api::object_ptr<td_api::Upda
} }
} }
void AnimationsManager::memory_cleanup() {
memory_cleanup(false);
}
void AnimationsManager::memory_cleanup(bool full) {
animations_.clear();
animations_.rehash(0);
saved_animation_ids_.clear();
saved_animation_file_ids_.clear();
}
void AnimationsManager::memory_stats(vector<string> &output) { void AnimationsManager::memory_stats(vector<string> &output) {
output.push_back("\"animations_\":"); output.push_back(std::to_string(animations_.size())); output.push_back("\"animations_\":"); output.push_back(std::to_string(animations_.size()));
output.push_back(","); output.push_back(",");

View File

@ -30,8 +30,6 @@ class AnimationsManager final : public Actor {
public: public:
AnimationsManager(Td *td, ActorShared<> parent); AnimationsManager(Td *td, ActorShared<> parent);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
int32 get_animation_duration(FileId file_id) const; int32 get_animation_duration(FileId file_id) const;
@ -115,8 +113,6 @@ class AnimationsManager final : public Actor {
FileId file_id; FileId file_id;
}; };
void memory_cleanup(bool full);
const Animation *get_animation(FileId file_id) const; const Animation *get_animation(FileId file_id) const;
FileId on_get_animation(unique_ptr<Animation> new_animation, bool replace); FileId on_get_animation(unique_ptr<Animation> new_animation, bool replace);

View File

@ -22,9 +22,7 @@ namespace td {
template <class StorerT> template <class StorerT>
void AnimationsManager::store_animation(FileId file_id, StorerT &storer) const { void AnimationsManager::store_animation(FileId file_id, StorerT &storer) const {
auto it = animations_.find(file_id); auto it = animations_.find(file_id);
if (it == animations_.end() || it->second == nullptr) { CHECK(it != animations_.end());
return;
}
const Animation *animation = it->second.get(); const Animation *animation = it->second.get();
bool has_animated_thumbnail = animation->animated_thumbnail.file_id.is_valid(); bool has_animated_thumbnail = animation->animated_thumbnail.file_id.is_valid();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();

View File

@ -25,9 +25,7 @@ AudiosManager::AudiosManager(Td *td) : td_(td) {
int32 AudiosManager::get_audio_duration(FileId file_id) const { int32 AudiosManager::get_audio_duration(FileId file_id) const {
auto it = audios_.find(file_id); auto it = audios_.find(file_id);
if (it == audios_.end() || it->second == nullptr) { CHECK(it != audios_.end());
return 0;
}
return it->second->duration; return it->second->duration;
} }
@ -37,13 +35,9 @@ tl_object_ptr<td_api::audio> AudiosManager::get_audio_object(FileId file_id) con
} }
auto it = audios_.find(file_id); auto it = audios_.find(file_id);
if (it == audios_.end()) { CHECK(it != audios_.end());
return nullptr;
}
auto audio = it->second.get(); auto audio = it->second.get();
if (audio == nullptr) { CHECK(audio != nullptr);
return nullptr;
}
return make_tl_object<td_api::audio>( return make_tl_object<td_api::audio>(
audio->duration, audio->title, audio->performer, audio->file_name, audio->mime_type, audio->duration, audio->title, audio->performer, audio->file_name, audio->mime_type,
get_minithumbnail_object(audio->minithumbnail), get_minithumbnail_object(audio->minithumbnail),
@ -93,8 +87,8 @@ FileId AudiosManager::on_get_audio(unique_ptr<Audio> new_audio, bool replace) {
const AudiosManager::Audio *AudiosManager::get_audio(FileId file_id) const { const AudiosManager::Audio *AudiosManager::get_audio(FileId file_id) const {
auto audio = audios_.find(file_id); auto audio = audios_.find(file_id);
if (audio == audios_.end() || audio->second == nullptr) { if (audio == audios_.end()) {
return make_unique<Audio>().get(); return nullptr;
} }
CHECK(audio->second->file_id == file_id); CHECK(audio->second->file_id == file_id);
@ -121,7 +115,7 @@ void AudiosManager::merge_audios(FileId new_id, FileId old_id, bool can_delete_o
CHECK(old_ != nullptr); CHECK(old_ != nullptr);
auto new_it = audios_.find(new_id); auto new_it = audios_.find(new_id);
if (new_it == audios_.end() || new_it->second == nullptr) { if (new_it == audios_.end()) {
auto &old = audios_[old_id]; auto &old = audios_[old_id];
if (!can_delete_old) { if (!can_delete_old) {
dup_audio(new_id, old_id); dup_audio(new_id, old_id);
@ -149,25 +143,19 @@ void AudiosManager::merge_audios(FileId new_id, FileId old_id, bool can_delete_o
string AudiosManager::get_audio_search_text(FileId file_id) const { string AudiosManager::get_audio_search_text(FileId file_id) const {
auto audio = get_audio(file_id); auto audio = get_audio(file_id);
if (audio == nullptr) { CHECK(audio != nullptr);
return "";
}
return PSTRING() << audio->file_name << " " << audio->title << " " << audio->performer; return PSTRING() << audio->file_name << " " << audio->title << " " << audio->performer;
} }
FileId AudiosManager::get_audio_thumbnail_file_id(FileId file_id) const { FileId AudiosManager::get_audio_thumbnail_file_id(FileId file_id) const {
auto audio = get_audio(file_id); auto audio = get_audio(file_id);
if (audio == nullptr) { CHECK(audio != nullptr);
return FileId();
}
return audio->thumbnail.file_id; return audio->thumbnail.file_id;
} }
void AudiosManager::delete_audio_thumbnail(FileId file_id) { void AudiosManager::delete_audio_thumbnail(FileId file_id) {
auto &audio = audios_[file_id]; auto &audio = audios_[file_id];
if (audio == nullptr) { CHECK(audio != nullptr);
return;
}
audio->thumbnail = PhotoSize(); audio->thumbnail = PhotoSize();
} }
@ -191,9 +179,7 @@ SecretInputMedia AudiosManager::get_secret_input_media(FileId audio_file_id,
tl_object_ptr<telegram_api::InputEncryptedFile> input_file, tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
const string &caption, BufferSlice thumbnail) const { const string &caption, BufferSlice thumbnail) const {
auto *audio = get_audio(audio_file_id); auto *audio = get_audio(audio_file_id);
if (audio == nullptr) { CHECK(audio != nullptr);
return SecretInputMedia{};
}
auto file_view = td_->file_manager_->get_file_view(audio_file_id); auto file_view = td_->file_manager_->get_file_view(audio_file_id);
auto &encryption_key = file_view.encryption_key(); auto &encryption_key = file_view.encryption_key();
if (!file_view.is_encrypted_secret() || encryption_key.empty()) { if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
@ -241,9 +227,7 @@ tl_object_ptr<telegram_api::InputMedia> AudiosManager::get_input_media(
if (input_file != nullptr) { if (input_file != nullptr) {
const Audio *audio = get_audio(file_id); const Audio *audio = get_audio(file_id);
if (audio == nullptr) { CHECK(audio != nullptr);
return nullptr;
}
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes; vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
attributes.push_back(make_tl_object<telegram_api::documentAttributeAudio>( attributes.push_back(make_tl_object<telegram_api::documentAttributeAudio>(
@ -269,10 +253,7 @@ tl_object_ptr<telegram_api::InputMedia> AudiosManager::get_input_media(
return nullptr; return nullptr;
} }
void AudiosManager::memory_cleanup() {
audios_.clear();
audios_.rehash(0);
}
void AudiosManager::memory_stats(vector<string> &output) { void AudiosManager::memory_stats(vector<string> &output) {
output.push_back("\"audios_\":"); output.push_back(std::to_string(audios_.size())); output.push_back("\"audios_\":"); output.push_back(std::to_string(audios_.size()));

View File

@ -26,8 +26,6 @@ class AudiosManager {
public: public:
explicit AudiosManager(Td *td); explicit AudiosManager(Td *td);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
int32 get_audio_duration(FileId file_id) const; int32 get_audio_duration(FileId file_id) const;

View File

@ -22,9 +22,7 @@ namespace td {
template <class StorerT> template <class StorerT>
void AudiosManager::store_audio(FileId file_id, StorerT &storer) const { void AudiosManager::store_audio(FileId file_id, StorerT &storer) const {
auto it = audios_.find(file_id); auto it = audios_.find(file_id);
if (it == audios_.end() || it->second == nullptr) { CHECK(it != audios_.end());
return;
}
const Audio *audio = it->second.get(); const Audio *audio = it->second.get();
store(audio->file_name, storer); store(audio->file_name, storer);
store(audio->mime_type, storer); store(audio->mime_type, storer);

View File

@ -140,9 +140,7 @@ class UploadBackgroundQuery final : public Td::ResultHandler {
void send(FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file, const BackgroundType &type, void send(FileId file_id, tl_object_ptr<telegram_api::InputFile> &&input_file, const BackgroundType &type,
bool for_dark_theme) { bool for_dark_theme) {
if (input_file == nullptr) { CHECK(input_file != nullptr);
return;
}
file_id_ = file_id; file_id_ = file_id;
type_ = type; type_ = type;
for_dark_theme_ = for_dark_theme; for_dark_theme_ = for_dark_theme;
@ -773,7 +771,7 @@ void BackgroundManager::save_background_id(bool for_dark_theme) {
auto background_id = set_background_id_[for_dark_theme]; auto background_id = set_background_id_[for_dark_theme];
if (background_id.is_valid()) { if (background_id.is_valid()) {
const Background *background = get_background(background_id); const Background *background = get_background(background_id);
if (!(background != nullptr)) return; CHECK(background != nullptr);
BackgroundLogEvent log_event{*background, set_background_type_[for_dark_theme]}; BackgroundLogEvent log_event{*background, set_background_type_[for_dark_theme]};
G()->td_db()->get_binlog_pmc()->set(key, log_event_store(log_event).as_slice().str()); G()->td_db()->get_binlog_pmc()->set(key, log_event_store(log_event).as_slice().str());
} else { } else {
@ -826,9 +824,7 @@ void BackgroundManager::on_upload_background_file(FileId file_id, tl_object_ptr<
LOG(INFO) << "Background file " << file_id << " has been uploaded"; LOG(INFO) << "Background file " << file_id << " has been uploaded";
auto it = being_uploaded_files_.find(file_id); auto it = being_uploaded_files_.find(file_id);
if (it == being_uploaded_files_.end()) { CHECK(it != being_uploaded_files_.end());
return;
}
auto type = it->second.type; auto type = it->second.type;
auto for_dark_theme = it->second.for_dark_theme; auto for_dark_theme = it->second.for_dark_theme;
@ -849,9 +845,7 @@ void BackgroundManager::on_upload_background_file_error(FileId file_id, Status s
CHECK(status.is_error()); CHECK(status.is_error());
auto it = being_uploaded_files_.find(file_id); auto it = being_uploaded_files_.find(file_id);
if (it == being_uploaded_files_.end()) { CHECK(it != being_uploaded_files_.end());
return;
}
auto promise = std::move(it->second.promise); auto promise = std::move(it->second.promise);
@ -882,7 +876,7 @@ void BackgroundManager::do_upload_background_file(FileId file_id, const Backgrou
void BackgroundManager::on_uploaded_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme, void BackgroundManager::on_uploaded_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme,
telegram_api::object_ptr<telegram_api::WallPaper> wallpaper, telegram_api::object_ptr<telegram_api::WallPaper> wallpaper,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
if (!(wallpaper != nullptr)) promise.set_error(Status::Error(500, "Error")); CHECK(wallpaper != nullptr);
auto added_background = on_get_background(BackgroundId(), string(), std::move(wallpaper), true); auto added_background = on_get_background(BackgroundId(), string(), std::move(wallpaper), true);
auto background_id = added_background.first; auto background_id = added_background.first;
@ -894,7 +888,7 @@ void BackgroundManager::on_uploaded_background_file(FileId file_id, const Backgr
<< "Type of uploaded background has changed from " << type << " to " << added_background.second; << "Type of uploaded background has changed from " << type << " to " << added_background.second;
const auto *background = get_background(background_id); const auto *background = get_background(background_id);
if (!(background != nullptr)) return promise.set_error(Status::Error(500, "Error")); CHECK(background != nullptr);
if (!background->file_id.is_valid()) { if (!background->file_id.is_valid()) {
td_->file_manager_->cancel_upload(file_id); td_->file_manager_->cancel_upload(file_id);
return promise.set_error(Status::Error(500, "Receive wrong uploaded background without file")); return promise.set_error(Status::Error(500, "Receive wrong uploaded background without file"));
@ -966,12 +960,6 @@ void BackgroundManager::on_reset_background(Result<Unit> &&result, Promise<Unit>
if (result.is_error()) { if (result.is_error()) {
return promise.set_error(result.move_as_error()); return promise.set_error(result.move_as_error());
} }
reset_backgrounds_data();
promise.set_value(Unit());
}
void BackgroundManager::reset_backgrounds_data() {
installed_backgrounds_.clear(); installed_backgrounds_.clear();
set_background_id(BackgroundId(), BackgroundType(), false); set_background_id(BackgroundId(), BackgroundType(), false);
set_background_id(BackgroundId(), BackgroundType(), true); set_background_id(BackgroundId(), BackgroundType(), true);
@ -983,6 +971,8 @@ void BackgroundManager::reset_backgrounds_data() {
local_background_ids_[1].clear(); local_background_ids_[1].clear();
save_local_backgrounds(true); save_local_backgrounds(true);
} }
promise.set_value(Unit());
} }
void BackgroundManager::add_background(const Background &background, bool replace_type) { void BackgroundManager::add_background(const Background &background, bool replace_type) {
@ -1304,24 +1294,6 @@ void BackgroundManager::get_current_state(vector<td_api::object_ptr<td_api::Upda
updates.push_back(get_update_selected_background_object(true)); updates.push_back(get_update_selected_background_object(true));
} }
void BackgroundManager::memory_cleanup() {
memory_cleanup(false);
}
void BackgroundManager::memory_cleanup(bool full) {
backgrounds_.clear();
backgrounds_.rehash(0);
background_id_to_file_source_id_.clear();
background_id_to_file_source_id_.rehash(0);
name_to_background_id_.clear();
name_to_background_id_.rehash(0);
file_id_to_background_id_.clear();
file_id_to_background_id_.rehash(0);
loaded_from_database_backgrounds_.clear();
loaded_from_database_backgrounds_.rehash(0);
reset_backgrounds_data();
}
void BackgroundManager::memory_stats(vector<string> &output) { void BackgroundManager::memory_stats(vector<string> &output) {
output.push_back("\"backgrounds_\":"); output.push_back(std::to_string(backgrounds_.size())); output.push_back("\"backgrounds_\":"); output.push_back(std::to_string(backgrounds_.size()));
output.push_back(","); output.push_back(",");

View File

@ -34,8 +34,6 @@ class BackgroundManager final : public Actor {
public: public:
BackgroundManager(Td *td, ActorShared<> parent); BackgroundManager(Td *td, ActorShared<> parent);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
void get_backgrounds(bool for_dark_theme, Promise<td_api::object_ptr<td_api::backgrounds>> &&promise); void get_backgrounds(bool for_dark_theme, Promise<td_api::object_ptr<td_api::backgrounds>> &&promise);
@ -105,8 +103,6 @@ class BackgroundManager final : public Actor {
void tear_down() final; void tear_down() final;
void memory_cleanup(bool full);
static string get_background_database_key(bool for_dark_theme); static string get_background_database_key(bool for_dark_theme);
static string get_local_backgrounds_database_key(bool for_dark_theme); static string get_local_backgrounds_database_key(bool for_dark_theme);
@ -157,8 +153,6 @@ class BackgroundManager final : public Actor {
void on_reset_background(Result<Unit> &&result, Promise<Unit> &&promise); void on_reset_background(Result<Unit> &&result, Promise<Unit> &&promise);
void reset_backgrounds_data();
void upload_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme, Promise<Unit> &&promise); void upload_background_file(FileId file_id, const BackgroundType &type, bool for_dark_theme, Promise<Unit> &&promise);
void on_upload_background_file(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file); void on_upload_background_file(FileId file_id, tl_object_ptr<telegram_api::InputFile> input_file);

View File

@ -44,9 +44,7 @@ class GetBotCallbackAnswerQuery final : public Td::ResultHandler {
message_id_ = message_id; message_id_ = message_id;
auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read); auto input_peer = td->messages_manager_->get_input_peer(dialog_id, AccessRights::Read);
if (input_peer == nullptr) { CHECK(input_peer != nullptr);
return;
}
int32 flags = 0; int32 flags = 0;
BufferSlice data; BufferSlice data;

View File

@ -11,7 +11,6 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include <ctime>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
@ -19,7 +18,6 @@ namespace td {
class ChannelId { class ChannelId {
int64 id = 0; int64 id = 0;
int64 time_ = INT64_MAX;
public: public:
// the last (1 << 31) - 1 identifiers will be used for secret chat dialog identifiers // the last (1 << 31) - 1 identifiers will be used for secret chat dialog identifiers
@ -40,18 +38,6 @@ class ChannelId {
return id; return id;
} }
void set_time() {
time_ = std::time(nullptr);
}
int64 get_time() const {
return time_;
}
void reset_time() {
time_ = INT64_MAX;
}
bool operator==(const ChannelId &other) const { bool operator==(const ChannelId &other) const {
return id == other.id; return id == other.id;
} }

View File

@ -11,7 +11,6 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include <ctime>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
@ -19,17 +18,13 @@ namespace td {
class ChatId { class ChatId {
int64 id = 0; int64 id = 0;
int64 time_ = INT64_MAX;
public: public:
static constexpr int64 MAX_CHAT_ID = 999999999999ll; static constexpr int64 MAX_CHAT_ID = 999999999999ll;
explicit ChatId() { ChatId() = default;
set_time();
};
explicit ChatId(int64 chat_id) : id(chat_id) { explicit ChatId(int64 chat_id) : id(chat_id) {
set_time();
} }
template <class T, typename = std::enable_if_t<std::is_convertible<T, int64>::value>> template <class T, typename = std::enable_if_t<std::is_convertible<T, int64>::value>>
ChatId(T chat_id) = delete; ChatId(T chat_id) = delete;
@ -42,18 +37,6 @@ class ChatId {
return id; return id;
} }
void set_time() {
time_ = std::time(nullptr);
}
int64 get_time() const {
return time_;
}
void reset_time() {
time_ = INT64_MAX;
}
bool operator==(const ChatId &other) const { bool operator==(const ChatId &other) const {
return id == other.id; return id == other.id;
} }

View File

@ -8,7 +8,6 @@
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/TdCallback.h" #include "td/telegram/TdCallback.h"
#include "td/telegram/Log.h"
#include "td/actor/actor.h" #include "td/actor/actor.h"
#include "td/actor/ConcurrentScheduler.h" #include "td/actor/ConcurrentScheduler.h"

View File

@ -3427,10 +3427,6 @@ ContactsManager::~ContactsManager() = default;
void ContactsManager::tear_down() { void ContactsManager::tear_down() {
parent_.reset(); parent_.reset();
if (td_->memory_manager_->can_manage_memory()) {
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup(true);
}
} }
UserId ContactsManager::load_my_id() { UserId ContactsManager::load_my_id() {
@ -3468,7 +3464,7 @@ void ContactsManager::on_user_online_timeout(UserId user_id) {
} }
auto u = get_user(user_id); auto u = get_user(user_id);
if (u == nullptr) { return; } CHECK(u != nullptr);
CHECK(u->is_update_user_sent); CHECK(u->is_update_user_sent);
LOG(INFO) << "Update " << user_id << " online status to offline"; LOG(INFO) << "Update " << user_id << " online status to offline";
@ -3494,7 +3490,7 @@ void ContactsManager::on_channel_unban_timeout(ChannelId channel_id) {
} }
auto c = get_channel(channel_id); auto c = get_channel(channel_id);
if (c == nullptr) { return; } CHECK(c != nullptr);
auto old_status = c->status; auto old_status = c->status;
c->status.update_restrictions(); c->status.update_restrictions();
@ -3527,7 +3523,7 @@ void ContactsManager::on_user_nearby_timeout(UserId user_id) {
} }
auto u = get_user(user_id); auto u = get_user(user_id);
if (u == nullptr) { return; } CHECK(u != nullptr);
LOG(INFO) << "Remove " << user_id << " from nearby list"; LOG(INFO) << "Remove " << user_id << " from nearby list";
DialogId dialog_id(user_id); DialogId dialog_id(user_id);
@ -10097,14 +10093,10 @@ void ContactsManager::update_chat_full(ChatFull *chat_full, ChatId chat_id, cons
void ContactsManager::update_channel_full(ChannelFull *channel_full, ChannelId channel_id, const char *source, void ContactsManager::update_channel_full(ChannelFull *channel_full, ChannelId channel_id, const char *source,
bool from_database) { bool from_database) {
if (channel_full == nullptr) { CHECK(channel_full != nullptr);
return;
}
unavailable_channel_fulls_.erase(channel_id); // don't needed anymore unavailable_channel_fulls_.erase(channel_id); // don't needed anymore
if (!(channel_full->participant_count >= channel_full->administrator_count)) { CHECK(channel_full->participant_count >= channel_full->administrator_count);
return;
}
if (channel_full->is_slow_mode_next_send_date_changed) { if (channel_full->is_slow_mode_next_send_date_changed) {
auto now = G()->server_time(); auto now = G()->server_time();
@ -10143,9 +10135,7 @@ void ContactsManager::update_channel_full(ChannelFull *channel_full, ChannelId c
{ {
Channel *c = get_channel(channel_id); Channel *c = get_channel(channel_id);
if (!(c == nullptr || c->is_update_supergroup_sent)) { CHECK(c == nullptr || c->is_update_supergroup_sent);
return;
}
} }
if (!channel_full->is_update_channel_full_sent) { if (!channel_full->is_update_channel_full_sent) {
LOG(ERROR) << "Send partial updateSupergroupFullInfo for " << channel_id << " from " << source; LOG(ERROR) << "Send partial updateSupergroupFullInfo for " << channel_id << " from " << source;
@ -11475,9 +11465,8 @@ void ContactsManager::update_user_online_member_count(User *u) {
case DialogType::Chat: { case DialogType::Chat: {
auto chat_id = dialog_id.get_chat_id(); auto chat_id = dialog_id.get_chat_id();
auto chat_full = get_chat_full(chat_id); auto chat_full = get_chat_full(chat_id);
if (chat_full != nullptr) { CHECK(chat_full != nullptr);
update_chat_online_member_count(chat_full, chat_id, false); update_chat_online_member_count(chat_full, chat_id, false);
}
break; break;
} }
case DialogType::Channel: { case DialogType::Channel: {
@ -13661,8 +13650,6 @@ Result<ContactsManager::BotData> ContactsManager::get_bot_data(UserId user_id) c
return Status::Error(400, "Bot is inaccessible"); return Status::Error(400, "Bot is inaccessible");
} }
user_id.set_time(); // update last access time of UserId
BotData bot_data; BotData bot_data;
bot_data.username = bot->username; bot_data.username = bot->username;
bot_data.can_join_groups = bot->can_join_groups; bot_data.can_join_groups = bot->can_join_groups;
@ -13692,7 +13679,6 @@ const ContactsManager::User *ContactsManager::get_user(UserId user_id) const {
if (p == users_.end()) { if (p == users_.end()) {
return nullptr; return nullptr;
} else { } else {
user_id.set_time(); // update last access time of UserId
return p->second.get(); return p->second.get();
} }
} }
@ -13702,7 +13688,6 @@ ContactsManager::User *ContactsManager::get_user(UserId user_id) {
if (p == users_.end()) { if (p == users_.end()) {
return nullptr; return nullptr;
} else { } else {
user_id.set_time(); // update last access time of UserId
return p->second.get(); return p->second.get();
} }
} }
@ -13787,7 +13772,6 @@ bool ContactsManager::get_user(UserId user_id, int left_tries, Promise<Unit> &&p
return false; return false;
} }
user_id.set_time();
promise.set_value(Unit()); promise.set_value(Unit());
return true; return true;
} }
@ -13798,7 +13782,6 @@ ContactsManager::User *ContactsManager::add_user(UserId user_id, const char *sou
if (user_ptr == nullptr) { if (user_ptr == nullptr) {
user_ptr = make_unique<User>(); user_ptr = make_unique<User>();
} }
user_id.set_time();
return user_ptr.get(); return user_ptr.get();
} }
@ -13807,7 +13790,6 @@ const ContactsManager::UserFull *ContactsManager::get_user_full(UserId user_id)
if (p == users_full_.end()) { if (p == users_full_.end()) {
return nullptr; return nullptr;
} else { } else {
user_id.set_time();
return p->second.get(); return p->second.get();
} }
} }
@ -13817,7 +13799,6 @@ ContactsManager::UserFull *ContactsManager::get_user_full(UserId user_id) {
if (p == users_full_.end()) { if (p == users_full_.end()) {
return nullptr; return nullptr;
} else { } else {
user_id.set_time();
return p->second.get(); return p->second.get();
} }
} }
@ -13828,7 +13809,6 @@ ContactsManager::UserFull *ContactsManager::add_user_full(UserId user_id) {
if (user_full_ptr == nullptr) { if (user_full_ptr == nullptr) {
user_full_ptr = make_unique<UserFull>(); user_full_ptr = make_unique<UserFull>();
} }
user_id.set_time();
return user_full_ptr.get(); return user_full_ptr.get();
} }
@ -13842,7 +13822,6 @@ void ContactsManager::reload_user(UserId user_id, Promise<Unit> &&promise) {
if (input_user == nullptr) { if (input_user == nullptr) {
return promise.set_error(Status::Error(400, "User info not found")); return promise.set_error(Status::Error(400, "User info not found"));
} }
user_id.set_time();
// there is no much reason to combine different requests into one request // there is no much reason to combine different requests into one request
vector<tl_object_ptr<telegram_api::InputUser>> users; vector<tl_object_ptr<telegram_api::InputUser>> users;
@ -13875,14 +13854,12 @@ void ContactsManager::load_user_full(UserId user_id, bool force, Promise<Unit> &
send_get_user_full_query(user_id, std::move(input_user), Auto(), "load expired user_full"); send_get_user_full_query(user_id, std::move(input_user), Auto(), "load expired user_full");
} }
user_id.set_time();
promise.set_value(Unit()); promise.set_value(Unit());
} }
void ContactsManager::reload_user_full(UserId user_id) { void ContactsManager::reload_user_full(UserId user_id) {
auto input_user = get_input_user(user_id); auto input_user = get_input_user(user_id);
if (input_user != nullptr) { if (input_user != nullptr) {
user_id.set_time();
send_get_user_full_query(user_id, std::move(input_user), Auto(), "reload_user_full"); send_get_user_full_query(user_id, std::move(input_user), Auto(), "reload_user_full");
} }
} }
@ -14039,7 +14016,6 @@ const ContactsManager::Chat *ContactsManager::get_chat(ChatId chat_id) const {
if (p == chats_.end()) { if (p == chats_.end()) {
return nullptr; return nullptr;
} else { } else {
chat_id.set_time(); // update last access time of ChatId
return p->second.get(); return p->second.get();
} }
} }
@ -14049,7 +14025,6 @@ ContactsManager::Chat *ContactsManager::get_chat(ChatId chat_id) {
if (p == chats_.end()) { if (p == chats_.end()) {
return nullptr; return nullptr;
} else { } else {
chat_id.set_time(); // update last access time of ChatId
return p->second.get(); return p->second.get();
} }
} }
@ -14376,7 +14351,6 @@ const ContactsManager::Channel *ContactsManager::get_channel(ChannelId channel_i
if (p == channels_.end()) { if (p == channels_.end()) {
return nullptr; return nullptr;
} else { } else {
channel_id.set_time(); // update last access time of ChannelId
return p->second.get(); return p->second.get();
} }
} }
@ -14386,7 +14360,6 @@ ContactsManager::Channel *ContactsManager::get_channel(ChannelId channel_id) {
if (p == channels_.end()) { if (p == channels_.end()) {
return nullptr; return nullptr;
} else { } else {
channel_id.set_time(); // update last access time of ChannelId
return p->second.get(); return p->second.get();
} }
} }
@ -15904,7 +15877,7 @@ td_api::object_ptr<td_api::updateUser> ContactsManager::get_update_unknown_user_
int64 ContactsManager::get_user_id_object(UserId user_id, const char *source) const { int64 ContactsManager::get_user_id_object(UserId user_id, const char *source) const {
if (user_id.is_valid() && get_user(user_id) == nullptr && unknown_users_.count(user_id) == 0) { if (user_id.is_valid() && get_user(user_id) == nullptr && unknown_users_.count(user_id) == 0) {
LOG(WARNING) << "Have no info about " << user_id << " from " << source; LOG(ERROR) << "Have no info about " << user_id << " from " << source;
unknown_users_.insert(user_id); unknown_users_.insert(user_id);
send_closure(G()->td(), &Td::send_update, get_update_unknown_user_object(user_id)); send_closure(G()->td(), &Td::send_update, get_update_unknown_user_object(user_id));
} }
@ -15998,7 +15971,7 @@ td_api::object_ptr<td_api::updateBasicGroup> ContactsManager::get_update_unknown
int64 ContactsManager::get_basic_group_id_object(ChatId chat_id, const char *source) const { int64 ContactsManager::get_basic_group_id_object(ChatId chat_id, const char *source) const {
if (chat_id.is_valid() && get_chat(chat_id) == nullptr && unknown_chats_.count(chat_id) == 0) { if (chat_id.is_valid() && get_chat(chat_id) == nullptr && unknown_chats_.count(chat_id) == 0) {
LOG(WARNING) << "Have no info about " << chat_id << " from " << source; LOG(ERROR) << "Have no info about " << chat_id << " from " << source;
unknown_chats_.insert(chat_id); unknown_chats_.insert(chat_id);
send_closure(G()->td(), &Td::send_update, get_update_unknown_basic_group_object(chat_id)); send_closure(G()->td(), &Td::send_update, get_update_unknown_basic_group_object(chat_id));
} }
@ -16052,7 +16025,7 @@ td_api::object_ptr<td_api::updateSupergroup> ContactsManager::get_update_unknown
int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char *source) const { int64 ContactsManager::get_supergroup_id_object(ChannelId channel_id, const char *source) const {
if (channel_id.is_valid() && get_channel(channel_id) == nullptr && unknown_channels_.count(channel_id) == 0) { if (channel_id.is_valid() && get_channel(channel_id) == nullptr && unknown_channels_.count(channel_id) == 0) {
LOG(WARNING) << "Have no info about " << channel_id << " received from " << source; LOG(ERROR) << "Have no info about " << channel_id << " received from " << source;
unknown_channels_.insert(channel_id); unknown_channels_.insert(channel_id);
send_closure(G()->td(), &Td::send_update, get_update_unknown_supergroup_object(channel_id)); send_closure(G()->td(), &Td::send_update, get_update_unknown_supergroup_object(channel_id));
} }
@ -16080,9 +16053,7 @@ tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_i
tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_info_object( tl_object_ptr<td_api::supergroupFullInfo> ContactsManager::get_supergroup_full_info_object(
const ChannelFull *channel_full, ChannelId channel_id) const { const ChannelFull *channel_full, ChannelId channel_id) const {
if(channel_full == nullptr) { CHECK(channel_full != nullptr);
return nullptr;
}
double slow_mode_delay_expires_in = 0; double slow_mode_delay_expires_in = 0;
if (channel_full->slow_mode_next_send_date != 0) { if (channel_full->slow_mode_next_send_date != 0) {
slow_mode_delay_expires_in = max(channel_full->slow_mode_next_send_date - G()->server_time(), 1e-3); slow_mode_delay_expires_in = max(channel_full->slow_mode_next_send_date - G()->server_time(), 1e-3);
@ -16127,7 +16098,7 @@ td_api::object_ptr<td_api::updateSecretChat> ContactsManager::get_update_unknown
int32 ContactsManager::get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const { int32 ContactsManager::get_secret_chat_id_object(SecretChatId secret_chat_id, const char *source) const {
if (secret_chat_id.is_valid() && get_secret_chat(secret_chat_id) == nullptr && if (secret_chat_id.is_valid() && get_secret_chat(secret_chat_id) == nullptr &&
unknown_secret_chats_.count(secret_chat_id) == 0) { unknown_secret_chats_.count(secret_chat_id) == 0) {
LOG(WARNING) << "Have no info about " << secret_chat_id << " from " << source; LOG(ERROR) << "Have no info about " << secret_chat_id << " from " << source;
unknown_secret_chats_.insert(secret_chat_id); unknown_secret_chats_.insert(secret_chat_id);
send_closure(G()->td(), &Td::send_update, get_update_unknown_secret_chat_object(secret_chat_id)); send_closure(G()->td(), &Td::send_update, get_update_unknown_secret_chat_object(secret_chat_id));
} }
@ -16314,171 +16285,6 @@ void ContactsManager::get_current_state(vector<td_api::object_ptr<td_api::Update
} }
} }
void ContactsManager::memory_cleanup() {
memory_cleanup(false);
}
void ContactsManager::memory_cleanup(bool full) {
auto time = std::time(nullptr);
auto user_ttl = full ? 0 : !G()->shared_config().get_option_integer("delete_user_reference_after_seconds", 3600);
auto chat_ttl = full ? 0 : !G()->shared_config().get_option_integer("delete_chat_reference_after_seconds", 3600);
auto chat_access_hash_cleanup = full ? true : !G()->shared_config().get_option_boolean("experiment_enable_chat_access_hash_cleanup", true);
/* DESTROY INVALID USERS */
if (full) {
users_.clear();
} else {
auto it = users_.begin();
while (it != users_.end()) {
//auto &user = it->second;
auto user_id = it->first;
auto is_invalid = time - user_id.get_time() > user_ttl;
if (is_invalid) {
user_id.reset_time();
it = users_.erase(it);
} else {
it++;
}
}
}
users_.rehash(0);
users_full_.clear();
users_full_.rehash(0);
user_photos_.clear();
user_photos_.rehash(0);
unknown_users_.clear();
unknown_users_.rehash(0);
user_profile_photo_file_source_ids_.clear();
user_profile_photo_file_source_ids_.rehash(0);
my_photo_file_id_.clear();
my_photo_file_id_.rehash(0);
if (full || chat_access_hash_cleanup) {
/* DESTROY INVALID CHATS */
if (full) {
chats_.clear();
} else {
auto it = chats_.begin();
while (it != chats_.end()) {
//auto &chat = it->second;
auto chat_id = it->first;
auto is_invalid = time - chat_id.get_time() > chat_ttl;
if (is_invalid) {
chat_id.reset_time();
it = chats_.erase(it);
} else {
it++;
}
}
}
chats_.rehash(0);
}
chats_full_.clear();
chats_full_.rehash(0);
unknown_chats_.clear();
unknown_chats_.rehash(0);
if (full || chat_access_hash_cleanup) {
chat_full_file_source_ids_.clear();
chat_full_file_source_ids_.rehash(0);
min_channels_.clear();
min_channels_.rehash(0);
/* DESTROY INVALID CHANNELS */
if (full) {
channels_.clear();
} else {
auto it = channels_.begin();
while (it != channels_.end()) {
//auto &channel = it->second;
auto channel_id = it->first;
auto is_invalid = time - channel_id.get_time() > chat_ttl;
if (is_invalid) {
channel_id.reset_time();
it = channels_.erase(it);
} else {
it++;
}
}
}
channels_.rehash(0);
channels_full_.clear();
channels_full_.rehash(0);
}
unknown_channels_.clear();
unknown_channels_.rehash(0);
if (full || chat_access_hash_cleanup) {
channel_full_file_source_ids_.clear();
channel_full_file_source_ids_.rehash(0);
}
if (full) {
secret_chats_.clear();
secret_chats_.rehash(0);
unknown_secret_chats_.clear();
unknown_secret_chats_.rehash(0);
secret_chats_with_user_.clear();
secret_chats_with_user_.rehash(0);
}
invite_link_infos_.clear();
invite_link_infos_.rehash(0);
dialog_access_by_invite_link_.clear();
dialog_access_by_invite_link_.rehash(0);
load_user_from_database_queries_.clear();
load_user_from_database_queries_.rehash(0);
loaded_from_database_users_.clear();
loaded_from_database_users_.rehash(0);
unavailable_user_fulls_.clear();
unavailable_user_fulls_.rehash(0);
load_chat_from_database_queries_.clear();
load_chat_from_database_queries_.rehash(0);
loaded_from_database_chats_.clear();
loaded_from_database_chats_.rehash(0);
unavailable_chat_fulls_.clear();
unavailable_chat_fulls_.rehash(0);
load_channel_from_database_queries_.clear();
load_channel_from_database_queries_.rehash(0);
loaded_from_database_channels_.clear();
loaded_from_database_channels_.rehash(0);
unavailable_channel_fulls_.clear();
unavailable_channel_fulls_.rehash(0);
if (full) {
load_secret_chat_from_database_queries_.clear();
load_secret_chat_from_database_queries_.rehash(0);
loaded_from_database_secret_chats_.clear();
loaded_from_database_secret_chats_.rehash(0);
}
dialog_administrators_.clear();
dialog_administrators_.rehash(0);
uploaded_profile_photos_.clear();
uploaded_profile_photos_.rehash(0);
imported_contacts_.clear();
imported_contacts_.rehash(0);
cached_channel_participants_.clear();
cached_channel_participants_.rehash(0);
load_contacts_queries_.clear();
load_imported_contacts_queries_.clear();
all_imported_contacts_.clear();
users_nearby_.clear();
channels_nearby_.clear();
all_users_nearby_.clear();
all_users_nearby_.rehash(0);
linked_channel_ids_.clear();
linked_channel_ids_.rehash(0);
restricted_user_ids_.clear();
restricted_user_ids_.rehash(0);
restricted_channel_ids_.clear();
restricted_channel_ids_.rehash(0);
next_all_imported_contacts_.clear();
imported_contact_user_ids_.clear();
unimported_contact_invites_.clear();
}
void ContactsManager::memory_stats(vector<string> &output) { void ContactsManager::memory_stats(vector<string> &output) {
output.push_back("\"users_\":"); output.push_back(std::to_string(users_.size())); output.push_back("\"users_\":"); output.push_back(std::to_string(users_.size()));

View File

@ -68,8 +68,6 @@ class ContactsManager final : public Actor {
static UserId load_my_id(); static UserId load_my_id();
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
static UserId get_user_id(const tl_object_ptr<telegram_api::User> &user); static UserId get_user_id(const tl_object_ptr<telegram_api::User> &user);
@ -1094,8 +1092,6 @@ class ContactsManager final : public Actor {
static constexpr int32 ACCOUNT_UPDATE_LAST_NAME = 1 << 1; static constexpr int32 ACCOUNT_UPDATE_LAST_NAME = 1 << 1;
static constexpr int32 ACCOUNT_UPDATE_ABOUT = 1 << 2; static constexpr int32 ACCOUNT_UPDATE_ABOUT = 1 << 2;
void memory_cleanup(bool full);
static bool have_input_peer_user(const User *u, AccessRights access_rights); static bool have_input_peer_user(const User *u, AccessRights access_rights);
static bool have_input_peer_chat(const Chat *c, AccessRights access_rights); static bool have_input_peer_chat(const Chat *c, AccessRights access_rights);
bool have_input_peer_channel(const Channel *c, ChannelId channel_id, AccessRights access_rights, bool have_input_peer_channel(const Channel *c, ChannelId channel_id, AccessRights access_rights,

View File

@ -13,9 +13,10 @@
#include "td/telegram/Td.h" #include "td/telegram/Td.h"
#include "td/telegram/VideoNotesManager.h" #include "td/telegram/VideoNotesManager.h"
#include "td/telegram/VideosManager.h" #include "td/telegram/VideosManager.h"
#include "td/telegram/Global.h"
#include "td/telegram/ConfigShared.h"
#include "td/utils/algorithm.h" #include "td/utils/algorithm.h"
#include "Document.hpp"
namespace td { namespace td {

View File

@ -33,9 +33,7 @@ namespace td {
template <class StorerT> template <class StorerT>
void store(const Document &document, StorerT &storer) { void store(const Document &document, StorerT &storer) {
Td *td = storer.context()->td().get_actor_unsafe(); Td *td = storer.context()->td().get_actor_unsafe();
if (td == nullptr) { CHECK(td != nullptr);
return;
}
store(document.type, storer); store(document.type, storer);
switch (document.type) { switch (document.type) {
@ -69,9 +67,7 @@ void store(const Document &document, StorerT &storer) {
template <class ParserT> template <class ParserT>
void parse(Document &document, ParserT &parser) { void parse(Document &document, ParserT &parser) {
Td *td = parser.context()->td().get_actor_unsafe(); Td *td = parser.context()->td().get_actor_unsafe();
if (td == nullptr) { CHECK(td != nullptr);
return;
}
parse(document.type, parser); parse(document.type, parser);
switch (document.type) { switch (document.type) {

View File

@ -52,11 +52,10 @@ tl_object_ptr<td_api::document> DocumentsManager::get_document_object(FileId fil
return nullptr; return nullptr;
} }
auto document_it = documents_.find(file_id); auto it = documents_.find(file_id);
if (document_it == documents_.end() || document_it->second == nullptr) { CHECK(it != documents_.end());
return nullptr; auto document = it->second.get();
} CHECK(document != nullptr);
auto document = document_it->second.get();
return make_tl_object<td_api::document>( return make_tl_object<td_api::document>(
document->file_name, document->mime_type, get_minithumbnail_object(document->minithumbnail), document->file_name, document->mime_type, get_minithumbnail_object(document->minithumbnail),
get_thumbnail_object(td_->file_manager_.get(), document->thumbnail, thumbnail_format), get_thumbnail_object(td_->file_manager_.get(), document->thumbnail, thumbnail_format),
@ -114,7 +113,7 @@ Document DocumentsManager::on_get_document(RemoteDocument remote_document, Dialo
auto video_dimensions = get_dimensions(video->w_, video->h_, "documentAttributeVideo"); auto video_dimensions = get_dimensions(video->w_, video->h_, "documentAttributeVideo");
if (dimensions.width == 0 || (video_dimensions.width != 0 && video_dimensions != dimensions)) { if (dimensions.width == 0 || (video_dimensions.width != 0 && video_dimensions != dimensions)) {
if (dimensions.width != 0) { if (dimensions.width != 0) {
LOG(INFO) << "Receive ambiguous video dimensions " << dimensions << " and " << video_dimensions; LOG(ERROR) << "Receive ambiguous video dimensions " << dimensions << " and " << video_dimensions;
} }
dimensions = video_dimensions; dimensions = video_dimensions;
} }
@ -524,13 +523,11 @@ void DocumentsManager::create_document(FileId file_id, string minithumbnail, Pho
const DocumentsManager::GeneralDocument *DocumentsManager::get_document(FileId file_id) const { const DocumentsManager::GeneralDocument *DocumentsManager::get_document(FileId file_id) const {
auto document = documents_.find(file_id); auto document = documents_.find(file_id);
if (document == documents_.end()) {
if (document == documents_.end() || return nullptr;
document->second == nullptr ||
document->second->file_id != file_id) {
return make_unique<GeneralDocument>().get();
} }
CHECK(document->second->file_id == file_id);
return document->second.get(); return document->second.get();
} }
@ -560,9 +557,7 @@ SecretInputMedia DocumentsManager::get_secret_input_media(FileId document_file_i
tl_object_ptr<telegram_api::InputEncryptedFile> input_file, tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
const string &caption, BufferSlice thumbnail) const { const string &caption, BufferSlice thumbnail) const {
const GeneralDocument *document = get_document(document_file_id); const GeneralDocument *document = get_document(document_file_id);
if (document == nullptr) { CHECK(document != nullptr);
return SecretInputMedia{};
}
auto file_view = td_->file_manager_->get_file_view(document_file_id); auto file_view = td_->file_manager_->get_file_view(document_file_id);
auto &encryption_key = file_view.encryption_key(); auto &encryption_key = file_view.encryption_key();
if (!file_view.is_encrypted_secret() || encryption_key.empty()) { if (!file_view.is_encrypted_secret() || encryption_key.empty()) {
@ -606,9 +601,7 @@ tl_object_ptr<telegram_api::InputMedia> DocumentsManager::get_input_media(
if (input_file != nullptr) { if (input_file != nullptr) {
const GeneralDocument *document = get_document(file_id); const GeneralDocument *document = get_document(file_id);
if (document == nullptr) { CHECK(document != nullptr);
return nullptr;
}
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes; vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
if (document->file_name.size()) { if (document->file_name.size()) {
@ -633,18 +626,14 @@ tl_object_ptr<telegram_api::InputMedia> DocumentsManager::get_input_media(
FileId DocumentsManager::get_document_thumbnail_file_id(FileId file_id) const { FileId DocumentsManager::get_document_thumbnail_file_id(FileId file_id) const {
auto document = get_document(file_id); auto document = get_document(file_id);
if (document == nullptr) { CHECK(document != nullptr);
return FileId();
}
return document->thumbnail.file_id; return document->thumbnail.file_id;
} }
void DocumentsManager::delete_document_thumbnail(FileId file_id) { void DocumentsManager::delete_document_thumbnail(FileId file_id) {
auto document_it = documents_.find(file_id); auto &document = documents_[file_id];
if (document_it == documents_.end() || document_it->second == nullptr) { CHECK(document != nullptr);
return; document->thumbnail = PhotoSize();
}
document_it->second->thumbnail = PhotoSize();
} }
FileId DocumentsManager::dup_document(FileId new_id, FileId old_id) { FileId DocumentsManager::dup_document(FileId new_id, FileId old_id) {
@ -667,17 +656,14 @@ void DocumentsManager::merge_documents(FileId new_id, FileId old_id, bool can_de
CHECK(old_ != nullptr); CHECK(old_ != nullptr);
auto new_it = documents_.find(new_id); auto new_it = documents_.find(new_id);
if (new_it == documents_.end() || new_it->second == nullptr) { if (new_it == documents_.end()) {
auto old_it = documents_.find(old_id); auto &old = documents_[old_id];
if (old_it != documents_.end() && old_it->second != nullptr) {
auto &old = old_it->second;
if (!can_delete_old) { if (!can_delete_old) {
dup_document(new_id, old_id); dup_document(new_id, old_id);
} else { } else {
old->file_id = new_id; old->file_id = new_id;
documents_.emplace(new_id, std::move(old)); documents_.emplace(new_id, std::move(old));
} }
}
} else { } else {
GeneralDocument *new_ = new_it->second.get(); GeneralDocument *new_ = new_it->second.get();
CHECK(new_ != nullptr); CHECK(new_ != nullptr);
@ -692,10 +678,6 @@ void DocumentsManager::merge_documents(FileId new_id, FileId old_id, bool can_de
} }
} }
void DocumentsManager::memory_cleanup() {
documents_.clear();
documents_.rehash(0);
}
void DocumentsManager::memory_stats(vector<string> &output) { void DocumentsManager::memory_stats(vector<string> &output) {
output.push_back("\"documents_\":"); output.push_back(std::to_string(documents_.size())); output.push_back("\"documents_\":"); output.push_back(std::to_string(documents_.size()));
} }

View File

@ -77,8 +77,6 @@ class DocumentsManager {
tl_object_ptr<td_api::document> get_document_object(FileId file_id, PhotoFormat thumbnail_format) const; tl_object_ptr<td_api::document> get_document_object(FileId file_id, PhotoFormat thumbnail_format) const;
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
Document on_get_document(RemoteDocument remote_document, DialogId owner_dialog_id, Document on_get_document(RemoteDocument remote_document, DialogId owner_dialog_id,

View File

@ -21,15 +21,10 @@ namespace td {
template <class StorerT> template <class StorerT>
void DocumentsManager::store_document(FileId file_id, StorerT &storer) const { void DocumentsManager::store_document(FileId file_id, StorerT &storer) const {
//LOG(DEBUG) << "Store document " << file_id; LOG(DEBUG) << "Store document " << file_id;
auto it = documents_.find(file_id); auto it = documents_.find(file_id);
if (it == documents_.end() || it->second == nullptr) { CHECK(it != documents_.end());
return;
}
const GeneralDocument *document = it->second.get(); const GeneralDocument *document = it->second.get();
if (document == nullptr) {
return;
}
store(document->file_name, storer); store(document->file_name, storer);
store(document->mime_type, storer); store(document->mime_type, storer);
store(document->minithumbnail, storer); store(document->minithumbnail, storer);
@ -65,7 +60,6 @@ FileId DocumentsManager::parse_document(ParserT &parser) {
parse(document->thumbnail, parser); parse(document->thumbnail, parser);
parse(document->file_id, parser); parse(document->file_id, parser);
LOG(DEBUG) << "Parsed document " << document->file_id; LOG(DEBUG) << "Parsed document " << document->file_id;
if (parser.get_error() != nullptr || !document->file_id.is_valid()) { if (parser.get_error() != nullptr || !document->file_id.is_valid()) {
return FileId(); return FileId();

View File

@ -61,15 +61,14 @@ fileSourceSupergroupFull supergroup_id:int32 = FileSource; // repa
*/ */
FileSourceId FileReferenceManager::get_current_file_source_id() const { FileSourceId FileReferenceManager::get_current_file_source_id() const {
return FileSourceId(narrow_cast<int32>((int32) unique_file_source_id)); return FileSourceId(narrow_cast<int32>(file_sources_.size()));
} }
template <class T> template <class T>
FileSourceId FileReferenceManager::add_file_source_id(T source, Slice source_str) { FileSourceId FileReferenceManager::add_file_source_id(T source, Slice source_str) {
auto source_id = ++unique_file_source_id; file_sources_.emplace_back(std::move(source));
file_sources_[source_id] = (std::move(source)); VLOG(file_references) << "Create file source " << file_sources_.size() << " for " << source_str;
VLOG(file_references) << "Create file source " << source_id << " for " << source_str; return get_current_file_source_id();
return FileSourceId(narrow_cast<int32>((int32) source_id));
} }
FileSourceId FileReferenceManager::create_message_file_source(FullMessageId full_message_id) { FileSourceId FileReferenceManager::create_message_file_source(FullMessageId full_message_id) {
@ -142,20 +141,14 @@ vector<FileSourceId> FileReferenceManager::get_some_file_sources(NodeId node_id)
return it->second.file_source_ids.get_some_elements(); return it->second.file_source_ids.get_some_elements();
} }
vector<FileSourceId> FileReferenceManager::get_all_file_sources(NodeId node_id) {
auto it = nodes_.find(node_id);
if (it == nodes_.end()) {
return {};
}
return it->second.file_source_ids.get_all_elements();
}
vector<FullMessageId> FileReferenceManager::get_some_message_file_sources(NodeId node_id) { vector<FullMessageId> FileReferenceManager::get_some_message_file_sources(NodeId node_id) {
auto file_source_ids = get_some_file_sources(node_id); auto file_source_ids = get_some_file_sources(node_id);
vector<FullMessageId> result; vector<FullMessageId> result;
for (auto file_source_id : file_source_ids) { for (auto file_source_id : file_source_ids) {
const auto &file_source = file_sources_[file_source_id.get()]; auto index = static_cast<size_t>(file_source_id.get()) - 1;
CHECK(index < file_sources_.size());
const auto &file_source = file_sources_[index];
if (file_source.get_offset() == 0) { if (file_source.get_offset() == 0) {
result.push_back(file_source.get<FileSourceMessage>().full_message_id); result.push_back(file_source.get<FileSourceMessage>().full_message_id);
} }
@ -258,7 +251,9 @@ void FileReferenceManager::send_query(Destination dest, FileSourceId file_source
send_closure(file_manager, &FileManager::on_file_reference_repaired, dest.node_id, file_source_id, send_closure(file_manager, &FileManager::on_file_reference_repaired, dest.node_id, file_source_id,
std::move(result), std::move(new_promise)); std::move(result), std::move(new_promise));
}); });
file_sources_[file_source_id.get()].visit(overloaded( auto index = static_cast<size_t>(file_source_id.get()) - 1;
CHECK(index < file_sources_.size());
file_sources_[index].visit(overloaded(
[&](const FileSourceMessage &source) { [&](const FileSourceMessage &source) {
send_closure_later(G()->messages_manager(), &MessagesManager::get_message_from_server, source.full_message_id, send_closure_later(G()->messages_manager(), &MessagesManager::get_message_from_server, source.full_message_id,
std::move(promise), "FileSourceMessage", nullptr); std::move(promise), "FileSourceMessage", nullptr);
@ -382,72 +377,6 @@ void FileReferenceManager::reload_photo(PhotoSizeSource source, Promise<Unit> pr
} }
} }
void FileReferenceManager::memory_cleanup() {
if (!G()->shared_config().get_option_boolean("experiment_enable_file_reference_cleanup", true)) {
return;
}
auto print_debug_messages = G()->shared_config().get_option_boolean("experiment_debug_file_reference_cleanup", false);
if (print_debug_messages) LOG(ERROR) << "memory_cleanup begin";
// Iterate all file sources and delete the unused ones
auto file_source_it = file_sources_.begin();
while (file_source_it != file_sources_.end()) {
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop begin";
auto source_id = file_source_it->first;
// Mark immediately the file source as unused
auto file_source_unused = true;
// Iterate all the file nodes while the source is unused
auto file_nodes_it = nodes_.begin();
while (file_nodes_it != nodes_.end() && file_source_unused) {
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> file_nodes loop begin";
// Get all the file sources related to the current file node
auto elements = get_all_file_sources(file_nodes_it->first);
// Iterate all the file sources related to the current file node
auto elements_it = elements.begin();
while (elements_it != elements.end() && file_source_unused) {
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> file_nodes loop >> elements loop begin";
if (source_id == (u_long) elements_it->get()) {
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> file_nodes loop >> elements loop break";
file_source_unused = false;
} else {
elements_it++;
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> file_nodes loop >> elements loop next";
}
}
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> file_nodes loop >> elements loop end";
file_nodes_it++;
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> file_nodes loop next";
}
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> file_nodes loop end";
if (file_source_unused) {
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop >> remove element from file_source";
file_source_it = file_sources_.erase(file_source_it);
} else {
file_source_it++;
}
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop next";
}
if (print_debug_messages) LOG(ERROR) << "memory_cleanup >> file_source loop end";
if (print_debug_messages) LOG(ERROR) << "memory_cleanup end";
}
void FileReferenceManager::memory_cleanup(NodeId node_id) {
auto find_node = nodes_.find(node_id);
if (find_node != nodes_.end()) {
auto &node = find_node->second;
node.query.reset();
node.file_source_ids.reset_position();
nodes_.erase(node_id);
}
}
void FileReferenceManager::memory_stats(vector<string> &output) { void FileReferenceManager::memory_stats(vector<string> &output) {
output.push_back("\"nodes_\":"); output.push_back(std::to_string(nodes_.size())); output.push_back("\"nodes_\":"); output.push_back(std::to_string(nodes_.size()));
output.push_back(","); output.push_back(",");

View File

@ -72,12 +72,6 @@ class FileReferenceManager final : public Actor {
template <class ParserT> template <class ParserT>
FileSourceId parse_file_source(Td *td, ParserT &parser); FileSourceId parse_file_source(Td *td, ParserT &parser);
void memory_cleanup(NodeId node_id);
vector<FileSourceId> get_all_file_sources(NodeId node_id);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
private: private:
@ -145,10 +139,7 @@ class FileReferenceManager final : public Actor {
Variant<FileSourceMessage, FileSourceUserPhoto, FileSourceChatPhoto, FileSourceChannelPhoto, FileSourceWallpapers, Variant<FileSourceMessage, FileSourceUserPhoto, FileSourceChatPhoto, FileSourceChannelPhoto, FileSourceWallpapers,
FileSourceWebPage, FileSourceSavedAnimations, FileSourceRecentStickers, FileSourceFavoriteStickers, FileSourceWebPage, FileSourceSavedAnimations, FileSourceRecentStickers, FileSourceFavoriteStickers,
FileSourceBackground, FileSourceChatFull, FileSourceChannelFull>; FileSourceBackground, FileSourceChatFull, FileSourceChannelFull>;
vector<FileSource> file_sources_;
std::unordered_map<u_long, FileSource> file_sources_;
u_long unique_file_source_id = 0;
int64 query_generation_{0}; int64 query_generation_{0};

View File

@ -28,9 +28,9 @@ namespace td {
template <class StorerT> template <class StorerT>
void FileReferenceManager::store_file_source(FileSourceId file_source_id, StorerT &storer) const { void FileReferenceManager::store_file_source(FileSourceId file_source_id, StorerT &storer) const {
auto source_tuple = file_sources_.find(file_source_id.get()); auto index = static_cast<size_t>(file_source_id.get()) - 1;
auto source = source_tuple->second; CHECK(index < file_sources_.size());
auto &source = file_sources_[index];
td::store(source.get_offset(), storer); td::store(source.get_offset(), storer);
source.visit(overloaded([&](const FileSourceMessage &source) { td::store(source.full_message_id, storer); }, source.visit(overloaded([&](const FileSourceMessage &source) { td::store(source.full_message_id, storer); },
[&](const FileSourceUserPhoto &source) { [&](const FileSourceUserPhoto &source) {

View File

@ -938,30 +938,6 @@ GroupCallManager::~GroupCallManager() = default;
void GroupCallManager::tear_down() { void GroupCallManager::tear_down() {
parent_.reset(); parent_.reset();
if (td_->memory_manager_->can_manage_memory()) {
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup(true);
}
}
void GroupCallManager::memory_cleanup() {
memory_cleanup(false);
}
void GroupCallManager::memory_cleanup(bool full) {
this->group_call_participants_.clear();
this->group_call_participants_.rehash(0);
this->group_call_recent_speakers_.clear();
this->group_call_recent_speakers_.rehash(0);
this->group_calls_.clear();
this->group_calls_.rehash(0);
//todo: check if we can clear call ids vector
// this->input_group_call_ids_.clear();
this->pending_join_requests_.clear();
this->pending_join_requests_.rehash(0);
} }
void GroupCallManager::memory_stats(vector<string> &output) { void GroupCallManager::memory_stats(vector<string> &output) {
@ -1027,9 +1003,7 @@ void GroupCallManager::on_check_group_call_is_joined_timeout(GroupCallId group_c
auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok(); auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok();
auto *group_call = get_group_call(input_group_call_id); auto *group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
auto audio_source = group_call->audio_source; auto audio_source = group_call->audio_source;
if (!group_call->is_joined || is_group_call_being_joined(input_group_call_id) || if (!group_call->is_joined || is_group_call_being_joined(input_group_call_id) ||
check_group_call_is_joined_timeout_.has_timeout(group_call_id.get()) || audio_source == 0) { check_group_call_is_joined_timeout_.has_timeout(group_call_id.get()) || audio_source == 0) {
@ -1065,9 +1039,7 @@ void GroupCallManager::on_send_speaking_action_timeout(GroupCallId group_call_id
auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok(); auto input_group_call_id = get_input_group_call_id(group_call_id).move_as_ok();
auto *group_call = get_group_call(input_group_call_id); auto *group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited && group_call->dialog_id.is_valid())) { CHECK(group_call != nullptr && group_call->is_inited && group_call->dialog_id.is_valid());
return;
}
if (!group_call->is_joined || !group_call->is_speaking) { if (!group_call->is_joined || !group_call->is_speaking) {
return; return;
} }
@ -1385,9 +1357,7 @@ void GroupCallManager::on_update_group_call_rights(InputGroupCallId input_group_
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if (need_group_call_participants(input_group_call_id, group_call)) { if (need_group_call_participants(input_group_call_id, group_call)) {
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
try_load_group_call_administrators(input_group_call_id, group_call->dialog_id); try_load_group_call_administrators(input_group_call_id, group_call->dialog_id);
auto *group_call_participants = add_group_call_participants(input_group_call_id); auto *group_call_participants = add_group_call_participants(input_group_call_id);
@ -1468,9 +1438,7 @@ void GroupCallManager::finish_get_group_call(InputGroupCallId input_group_call_i
} }
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
for (auto &promise : promises) { for (auto &promise : promises) {
if (promise) { if (promise) {
promise.set_value(get_group_call_object(group_call, get_recent_speakers(group_call, false))); promise.set_value(get_group_call_object(group_call, get_recent_speakers(group_call, false)));
@ -1494,12 +1462,8 @@ void GroupCallManager::finish_check_group_call_is_joined(InputGroupCallId input_
} }
auto *group_call = get_group_call(input_group_call_id); auto *group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return; CHECK(audio_source != 0);
}
if(!(audio_source != 0)) {
return;
}
if (!group_call->is_joined || is_group_call_being_joined(input_group_call_id) || if (!group_call->is_joined || is_group_call_being_joined(input_group_call_id) ||
check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get()) || check_group_call_is_joined_timeout_.has_timeout(group_call->group_call_id.get()) ||
group_call->audio_source != audio_source) { group_call->audio_source != audio_source) {
@ -1601,9 +1565,7 @@ void GroupCallManager::on_get_group_call_participants(
bool is_sync = is_load && offset.empty(); bool is_sync = is_load && offset.empty();
if (is_sync) { if (is_sync) {
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
is_sync = group_call->syncing_participants; is_sync = group_call->syncing_participants;
if (is_sync) { if (is_sync) {
group_call->syncing_participants = false; group_call->syncing_participants = false;
@ -1637,9 +1599,7 @@ void GroupCallManager::on_get_group_call_participants(
if (is_empty || is_sync) { if (is_empty || is_sync) {
bool need_update = false; bool need_update = false;
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
if (is_empty && !group_call->loaded_all_participants) { if (is_empty && !group_call->loaded_all_participants) {
group_call->loaded_all_participants = true; group_call->loaded_all_participants = true;
need_update = true; need_update = true;
@ -1736,13 +1696,7 @@ void GroupCallManager::on_update_group_call_participants(
int32 video_diff = 0; int32 video_diff = 0;
bool need_update = false; bool need_update = false;
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if (group_call == nullptr) {
return;
}
for (auto &group_call_participant : participants) { for (auto &group_call_participant : participants) {
if (group_call_participant == nullptr) {
continue;
}
GroupCallParticipant participant(group_call_participant, version); GroupCallParticipant participant(group_call_participant, version);
if (!participant.is_valid()) { if (!participant.is_valid()) {
LOG(ERROR) << "Receive invalid " << to_string(group_call_participant); LOG(ERROR) << "Receive invalid " << to_string(group_call_participant);
@ -1856,9 +1810,7 @@ bool GroupCallManager::process_pending_group_call_participant_updates(InputGroup
return false; return false;
} }
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return false;
}
if (group_call->version == -1 || !group_call->is_active) { if (group_call->version == -1 || !group_call->is_active) {
return false; return false;
} }
@ -1972,9 +1924,7 @@ void GroupCallManager::sync_group_call_participants(InputGroupCallId input_group
} }
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if (!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
sync_participants_timeout_.cancel_timeout(group_call->group_call_id.get()); sync_participants_timeout_.cancel_timeout(group_call->group_call_id.get());
@ -2002,12 +1952,8 @@ void GroupCallManager::on_sync_group_call_participants(InputGroupCallId input_gr
if (result.is_error()) { if (result.is_error()) {
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if (!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return; CHECK(group_call->syncing_participants);
}
if (!(group_call->syncing_participants)) {
return;
}
group_call->syncing_participants = false; group_call->syncing_participants = false;
sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(), sync_participants_timeout_.add_timeout_in(group_call->group_call_id.get(),
@ -2239,9 +2185,7 @@ std::pair<int32, int32> GroupCallManager::process_group_call_participant(InputGr
if (participant.is_self) { if (participant.is_self) {
auto *group_call = get_group_call(input_group_call_id); auto *group_call = get_group_call(input_group_call_id);
if (!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return {0, 0};
}
auto can_self_unmute = group_call->is_active && !participant.get_is_muted_by_admin(); auto can_self_unmute = group_call->is_active && !participant.get_is_muted_by_admin();
if (can_self_unmute != group_call->can_self_unmute) { if (can_self_unmute != group_call->can_self_unmute) {
group_call->can_self_unmute = can_self_unmute; group_call->can_self_unmute = can_self_unmute;
@ -3994,9 +3938,7 @@ void GroupCallManager::load_group_call_participants(GroupCallId group_call_id, i
if (!need_group_call_participants(input_group_call_id, group_call)) { if (!need_group_call_participants(input_group_call_id, group_call)) {
return promise.set_error(Status::Error(400, "Can't load group call participants")); return promise.set_error(Status::Error(400, "Can't load group call participants"));
} }
if (!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return promise.set_error(Status::Error(400, "Internal error"));
}
if (group_call->loaded_all_participants) { if (group_call->loaded_all_participants) {
return promise.set_value(Unit()); return promise.set_value(Unit());
} }
@ -4066,9 +4008,7 @@ void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id,
} }
auto *group_call = get_group_call(input_group_call_id); auto *group_call = get_group_call(input_group_call_id);
if (!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
if (group_call->is_joined && group_call->audio_source == audio_source) { if (group_call->is_joined && group_call->audio_source == audio_source) {
on_group_call_left_impl(group_call, need_rejoin, "on_group_call_left"); on_group_call_left_impl(group_call, need_rejoin, "on_group_call_left");
send_update_group_call(group_call, "on_group_call_left"); send_update_group_call(group_call, "on_group_call_left");
@ -4076,9 +4016,9 @@ void GroupCallManager::on_group_call_left(InputGroupCallId input_group_call_id,
} }
void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_rejoin, const char *source) { void GroupCallManager::on_group_call_left_impl(GroupCall *group_call, bool need_rejoin, const char *source) {
if (!(group_call != nullptr && group_call->is_inited && group_call->is_joined)) { CHECK(group_call != nullptr && group_call->is_inited && group_call->is_joined);
return; LOG(INFO) << "Leave " << group_call->group_call_id << " in " << group_call->dialog_id
} << " with need_rejoin = " << need_rejoin << " from " << source;
group_call->is_joined = false; group_call->is_joined = false;
group_call->need_rejoin = need_rejoin && !group_call->is_being_left; group_call->need_rejoin = need_rejoin && !group_call->is_being_left;
if (group_call->need_rejoin && group_call->dialog_id.is_valid()) { if (group_call->need_rejoin && group_call->dialog_id.is_valid()) {
@ -4156,9 +4096,7 @@ bool GroupCallManager::try_clear_group_call_participants(InputGroupCallId input_
CHECK(participants != nullptr); CHECK(participants != nullptr);
group_call_participants_.erase(participants_it); group_call_participants_.erase(participants_it);
if (!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return false;
}
LOG(INFO) << "Clear participants in " << input_group_call_id << " from " << group_call->dialog_id; LOG(INFO) << "Clear participants in " << input_group_call_id << " from " << group_call->dialog_id;
if (group_call->loaded_all_participants) { if (group_call->loaded_all_participants) {
group_call->loaded_all_participants = false; group_call->loaded_all_participants = false;
@ -4441,9 +4379,7 @@ void GroupCallManager::on_receive_group_call_version(InputGroupCallId input_grou
if (!need_group_call_participants(input_group_call_id, group_call)) { if (!need_group_call_participants(input_group_call_id, group_call)) {
return; return;
} }
if (!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
if (group_call->version == -1) { if (group_call->version == -1) {
return; return;
} }
@ -4726,9 +4662,7 @@ void GroupCallManager::update_group_call_dialog(const GroupCall *group_call, con
vector<td_api::object_ptr<td_api::groupCallRecentSpeaker>> GroupCallManager::get_recent_speakers( vector<td_api::object_ptr<td_api::groupCallRecentSpeaker>> GroupCallManager::get_recent_speakers(
const GroupCall *group_call, bool for_update) { const GroupCall *group_call, bool for_update) {
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return Auto();
}
auto recent_speakers_it = group_call_recent_speakers_.find(group_call->group_call_id); auto recent_speakers_it = group_call_recent_speakers_.find(group_call->group_call_id);
if (recent_speakers_it == group_call_recent_speakers_.end()) { if (recent_speakers_it == group_call_recent_speakers_.end()) {
@ -4841,9 +4775,7 @@ void GroupCallManager::send_update_group_call_participant(InputGroupCallId input
return; return;
} }
auto group_call = get_group_call(input_group_call_id); auto group_call = get_group_call(input_group_call_id);
if(!(group_call != nullptr && group_call->is_inited)) { CHECK(group_call != nullptr && group_call->is_inited);
return;
}
send_update_group_call_participant(group_call->group_call_id, participant, source); send_update_group_call_participant(group_call->group_call_id, participant, source);
} }

View File

@ -39,8 +39,6 @@ class GroupCallManager final : public Actor {
GroupCallManager &operator=(GroupCallManager &&) = delete; GroupCallManager &operator=(GroupCallManager &&) = delete;
~GroupCallManager() final; ~GroupCallManager() final;
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
DialogId get_group_call_participant_id(const td_api::object_ptr<td_api::MessageSender> &message_sender); DialogId get_group_call_participant_id(const td_api::object_ptr<td_api::MessageSender> &message_sender);
@ -157,8 +155,6 @@ class GroupCallManager final : public Actor {
void tear_down() final; void tear_down() final;
void memory_cleanup(bool full);
static void on_update_group_call_participant_order_timeout_callback(void *group_call_manager_ptr, static void on_update_group_call_participant_order_timeout_callback(void *group_call_manager_ptr,
int64 group_call_id_int); int64 group_call_id_int);

View File

@ -174,10 +174,6 @@ InlineQueriesManager::InlineQueriesManager(Td *td, ActorShared<> parent) : td_(t
void InlineQueriesManager::tear_down() { void InlineQueriesManager::tear_down() {
parent_.reset(); parent_.reset();
if (td_->memory_manager_->can_manage_memory()) {
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup(true);
}
} }
void InlineQueriesManager::on_drop_inline_query_result_timeout_callback(void *inline_queries_manager_ptr, void InlineQueriesManager::on_drop_inline_query_result_timeout_callback(void *inline_queries_manager_ptr,
@ -1906,20 +1902,6 @@ void InlineQueriesManager::remove_recent_inline_bot(UserId bot_user_id, Promise<
promise.set_value(Unit()); promise.set_value(Unit());
} }
void InlineQueriesManager::memory_cleanup() {
memory_cleanup(false);
}
void InlineQueriesManager::memory_cleanup(bool full) {
recently_used_bot_user_ids_.clear();
inline_query_results_.clear();
inline_query_results_.rehash(0);
inline_message_contents_.clear();
inline_message_contents_.rehash(0);
query_id_to_bot_user_id_.clear();
query_id_to_bot_user_id_.rehash(0);
}
void InlineQueriesManager::memory_stats(vector<string> &output) { void InlineQueriesManager::memory_stats(vector<string> &output) {
output.push_back("\"recently_used_bot_user_ids_\":"); output.push_back(std::to_string(recently_used_bot_user_ids_.size())); output.push_back("\"recently_used_bot_user_ids_\":"); output.push_back(std::to_string(recently_used_bot_user_ids_.size()));
output.push_back(","); output.push_back(",");

View File

@ -38,8 +38,6 @@ class InlineQueriesManager final : public Actor {
public: public:
InlineQueriesManager(Td *td, ActorShared<> parent); InlineQueriesManager(Td *td, ActorShared<> parent);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
void after_get_difference(); void after_get_difference();
@ -118,8 +116,6 @@ class InlineQueriesManager final : public Actor {
void tear_down() final; void tear_down() final;
void memory_cleanup(bool full);
int32 recently_used_bots_loaded_ = 0; // 0 - not loaded, 1 - load request was sent, 2 - loaded int32 recently_used_bots_loaded_ = 0; // 0 - not loaded, 1 - load request was sent, 2 - loaded
MultiPromiseActor resolve_recent_inline_bots_multipromise_{"ResolveRecentInlineBotsMultiPromiseActor"}; MultiPromiseActor resolve_recent_inline_bots_multipromise_{"ResolveRecentInlineBotsMultiPromiseActor"};

View File

@ -70,9 +70,4 @@ void Log::set_fatal_error_callback(FatalErrorCallbackPtr callback) {
} }
} }
void Log::set_disable_death_handler(bool disabled) {
std::lock_guard<std::mutex> lock(log_mutex);
set_log_disable_death_handler(disabled);
}
} // namespace td } // namespace td

View File

@ -81,8 +81,6 @@ class Log {
* Pass nullptr to remove the callback. * Pass nullptr to remove the callback.
*/ */
static void set_fatal_error_callback(FatalErrorCallbackPtr callback); static void set_fatal_error_callback(FatalErrorCallbackPtr callback);
static void set_disable_death_handler(bool disabled);
}; };
} // namespace td } // namespace td

View File

@ -57,8 +57,7 @@ static const std::map<Slice, int *> log_tags{
ADD_TAG(proxy), ADD_TAG(net_query), ADD_TAG(td_requests), ADD_TAG(dc), ADD_TAG(proxy), ADD_TAG(net_query), ADD_TAG(td_requests), ADD_TAG(dc),
ADD_TAG(file_loader), ADD_TAG(mtproto), ADD_TAG(raw_mtproto), ADD_TAG(fd), ADD_TAG(file_loader), ADD_TAG(mtproto), ADD_TAG(raw_mtproto), ADD_TAG(fd),
ADD_TAG(actor), ADD_TAG(sqlite), ADD_TAG(notifications), ADD_TAG(get_difference), ADD_TAG(actor), ADD_TAG(sqlite), ADD_TAG(notifications), ADD_TAG(get_difference),
ADD_TAG(file_gc), ADD_TAG(config_recoverer), ADD_TAG(dns_resolver), ADD_TAG(file_references), ADD_TAG(file_gc), ADD_TAG(config_recoverer), ADD_TAG(dns_resolver), ADD_TAG(file_references)};
ADD_TAG(messages), ADD_TAG(postponed_pts_update), ADD_TAG(add_pending_update)};
#undef ADD_TAG #undef ADD_TAG
Status Logging::set_current_stream(td_api::object_ptr<td_api::LogStream> stream) { Status Logging::set_current_stream(td_api::object_ptr<td_api::LogStream> stream) {

View File

@ -75,40 +75,13 @@ MemoryManager::MemoryManager(Td *td, ActorShared<> parent) : td_(td), parent_(st
} }
void MemoryManager::start_up() { void MemoryManager::start_up() {
LOG(INFO) << "Start MemoryManager";
} }
void MemoryManager::tear_down() { void MemoryManager::tear_down() {
LOG(INFO) << "Stopping MemoryManager";
parent_.reset(); parent_.reset();
LOG(INFO) << "Stopped MemoryManager";
}
bool MemoryManager::can_manage_memory() const {
if (!(td_->auth_manager_->is_authorized() && !G()->close_flag())) {
return false;
}
if (!do_session_settings_allow_for_memory_management()) {
return false;
}
return true;
}
bool MemoryManager::do_session_settings_allow_for_memory_management() {
if (G()->parameters().use_message_db || G()->parameters().use_chat_info_db || G()->parameters().use_file_db) {
return false;
}
return true;
} }
void MemoryManager::get_memory_stats(bool full, Promise<MemoryStats> promise) const { void MemoryManager::get_memory_stats(bool full, Promise<MemoryStats> promise) const {
if (!can_manage_memory()) {
auto value = MemoryStats(R"({"warning": "OptimizeMemory is not enabled, please read the recommended options on README.md"})");
promise.set_value(std::move(value));
return;
}
vector<string> output = {"{"}; vector<string> output = {"{"};
output.push_back("\"memory_stats\":{"); output.push_back("\"memory_stats\":{");
@ -213,43 +186,6 @@ void MemoryManager::get_memory_stats(bool full, Promise<MemoryStats> promise) co
promise.set_value(std::move(value)); promise.set_value(std::move(value));
} }
void MemoryManager::clean_memory(bool full, Promise<Unit> promise) const {
if (!can_manage_memory()) {
if (!do_session_settings_allow_for_memory_management()) {
promise.set_error(Status::Error(405, "MEMORY_STATS_DISALLOWED"
" Session settings don't allow memory optimization."
" If you want to optimize memory, you should completely disable all databases."));
} else {
promise.set_error(Status::Error(405, "Can't manage memory now"));
}
return;
}
td_->messages_manager_->memory_cleanup();
td_->contacts_manager_->memory_cleanup();
td_->web_pages_manager_->memory_cleanup();
td_->stickers_manager_->memory_cleanup();
td_->documents_manager_->memory_cleanup();
td_->video_notes_manager_->memory_cleanup();
td_->videos_manager_->memory_cleanup();
td_->audios_manager_->memory_cleanup();
td_->animations_manager_->memory_cleanup();
td_->file_manager_->memory_cleanup();
td_->file_reference_manager_->memory_cleanup();
td_->group_call_manager_->memory_cleanup();
td_->background_manager_->memory_cleanup();
td_->inline_queries_manager_->memory_cleanup();
td_->poll_manager_->memory_cleanup();
#ifdef __linux__
#if defined(__GLIBC__) && !defined(__UCLIBC__) && !defined(__MUSL__)
malloc_trim(0);
#endif
#endif
promise.set_value(Unit());
}
void MemoryManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const { void MemoryManager::get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const {
if (td_->auth_manager_->is_bot()) { if (td_->auth_manager_->is_bot()) {
return; return;

View File

@ -48,14 +48,8 @@ class MemoryManager : public Actor {
public: public:
MemoryManager(Td *td, ActorShared<> parent); MemoryManager(Td *td, ActorShared<> parent);
bool can_manage_memory() const;
static bool do_session_settings_allow_for_memory_management();
void get_memory_stats(bool full, Promise<MemoryStats> promise) const; void get_memory_stats(bool full, Promise<MemoryStats> promise) const;
void clean_memory(bool full, Promise<Unit> promise) const;
void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const; void get_current_state(vector<td_api::object_ptr<td_api::Update>> &updates) const;
private: private:

File diff suppressed because it is too large Load Diff

View File

@ -141,8 +141,6 @@ class MessagesManager final : public Actor {
MessagesManager &operator=(MessagesManager &&) = delete; MessagesManager &operator=(MessagesManager &&) = delete;
~MessagesManager() final; ~MessagesManager() final;
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
td_api::object_ptr<td_api::MessageSender> get_message_sender_object_const(UserId user_id, DialogId dialog_id, td_api::object_ptr<td_api::MessageSender> get_message_sender_object_const(UserId user_id, DialogId dialog_id,
@ -1147,9 +1145,6 @@ class MessagesManager final : public Actor {
struct Dialog { struct Dialog {
DialogId dialog_id; DialogId dialog_id;
int64 time_ = INT64_MAX;
MessageId last_new_message_id; // identifier of the last known server message received from update, there should be MessageId last_new_message_id; // identifier of the last known server message received from update, there should be
// no server messages after it // no server messages after it
MessageId last_message_id; // identifier of the message after which currently there are no messages, i.e. a MessageId last_message_id; // identifier of the message after which currently there are no messages, i.e. a
@ -1357,18 +1352,6 @@ class MessagesManager final : public Actor {
Dialog &operator=(Dialog &&other) = delete; Dialog &operator=(Dialog &&other) = delete;
~Dialog(); ~Dialog();
void set_time() {
time_ = std::time(nullptr);
}
int64 get_time() const {
return time_;
}
void reset_time() {
time_ = INT64_MAX;
}
template <class StorerT> template <class StorerT>
void store(StorerT &storer) const; void store(StorerT &storer) const;
@ -1729,10 +1712,6 @@ class MessagesManager final : public Actor {
static constexpr bool DROP_SEND_MESSAGE_UPDATES = false; static constexpr bool DROP_SEND_MESSAGE_UPDATES = false;
void memory_cleanup(bool teardown);
void memory_cleanup(DialogId dialog_id, Dialog *d);
static FullMessageId get_full_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled); static FullMessageId get_full_message_id(const tl_object_ptr<telegram_api::Message> &message_ptr, bool is_scheduled);
static int32 get_message_date(const tl_object_ptr<telegram_api::Message> &message_ptr); static int32 get_message_date(const tl_object_ptr<telegram_api::Message> &message_ptr);
@ -2910,9 +2889,6 @@ class MessagesManager final : public Actor {
void on_channel_get_difference_timeout(DialogId dialog_id); void on_channel_get_difference_timeout(DialogId dialog_id);
void get_channel_difference_delayed(DialogId dialog_id, int32 pts, bool force, bool enable_reactive_channel_difference,
const char *source);
void get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source); void get_channel_difference(DialogId dialog_id, int32 pts, bool force, const char *source);
void do_get_channel_difference(DialogId dialog_id, int32 pts, bool force, void do_get_channel_difference(DialogId dialog_id, int32 pts, bool force,
@ -3244,14 +3220,6 @@ class MessagesManager final : public Actor {
}; };
std::unordered_map<int64, unique_ptr<PendingMessageImport>> pending_message_imports_; std::unordered_map<int64, unique_ptr<PendingMessageImport>> pending_message_imports_;
struct PendingChannelDifference {
DialogId dialog_id;
int32 pts;
bool force;
};
std::unordered_map<int64, PendingChannelDifference> pending_channel_difference_;
int64 last_pending_channel_difference_ = 0;
struct PendingMessageGroupSend { struct PendingMessageGroupSend {
DialogId dialog_id; DialogId dialog_id;
size_t finished_count = 0; size_t finished_count = 0;

View File

@ -461,9 +461,6 @@ Variant<PhotoSize, string> get_photo_size(FileManager *file_manager, PhotoSizeSo
AnimationSize get_animation_size(FileManager *file_manager, PhotoSizeSource source, int64 id, int64 access_hash, AnimationSize get_animation_size(FileManager *file_manager, PhotoSizeSource source, int64 id, int64 access_hash,
std::string file_reference, DcId dc_id, DialogId owner_dialog_id, std::string file_reference, DcId dc_id, DialogId owner_dialog_id,
tl_object_ptr<telegram_api::videoSize> &&size) { tl_object_ptr<telegram_api::videoSize> &&size) {
if (size == nullptr) {
return {};
}
CHECK(size != nullptr); CHECK(size != nullptr);
AnimationSize res; AnimationSize res;
if (size->type_ != "v" && size->type_ != "u") { if (size->type_ != "v" && size->type_ != "u") {

View File

@ -268,10 +268,6 @@ void PollManager::start_up() {
void PollManager::tear_down() { void PollManager::tear_down() {
parent_.reset(); parent_.reset();
if (td_->memory_manager_->can_manage_memory()) {
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup(true);
}
} }
PollManager::~PollManager() = default; PollManager::~PollManager() = default;
@ -344,7 +340,7 @@ void PollManager::save_poll(const Poll *poll, PollId poll_id) {
} }
LOG(INFO) << "Save " << poll_id << " to database"; LOG(INFO) << "Save " << poll_id << " to database";
if (!(poll != nullptr)) return; CHECK(poll != nullptr);
G()->td_db()->get_sqlite_pmc()->set(get_poll_database_key(poll_id), log_event_store(*poll).as_slice().str(), Auto()); G()->td_db()->get_sqlite_pmc()->set(get_poll_database_key(poll_id), log_event_store(*poll).as_slice().str(), Auto());
} }
@ -502,19 +498,7 @@ vector<int32> PollManager::get_vote_percentage(const vector<int32> &voter_counts
td_api::object_ptr<td_api::poll> PollManager::get_poll_object(PollId poll_id) const { td_api::object_ptr<td_api::poll> PollManager::get_poll_object(PollId poll_id) const {
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (!(poll != nullptr)) { CHECK(poll != nullptr);
//todo: find better alternative, rather than just creating a fake poll to avoid crashes...
vector<td_api::object_ptr<td_api::pollOption>> poll_options;
poll_options.push_back(td_api::make_object<td_api::pollOption>(
"empty", 0, 0, false,
false));
vector<int32> votes;
return td_api::make_object<td_api::poll>(
poll_id.get(), "empty question", std::move(poll_options), 0,
std::move(votes), true,
td_api::make_object<td_api::pollTypeRegular>(false),
1, G()->unix_time() - 1, true);
}
return get_poll_object(poll_id, poll); return get_poll_object(poll_id, poll);
} }
@ -638,9 +622,7 @@ PollId PollManager::create_poll(string &&question, vector<string> &&options, boo
} }
void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id, const char *source) { void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id, const char *source) {
if(!(have_poll(poll_id))) { CHECK(have_poll(poll_id));
return;
}
if (full_message_id.get_message_id().is_scheduled()) { if (full_message_id.get_message_id().is_scheduled()) {
return; return;
} }
@ -651,7 +633,7 @@ void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id, c
bool is_inserted = poll_messages_[poll_id].insert(full_message_id).second; bool is_inserted = poll_messages_[poll_id].insert(full_message_id).second;
LOG_CHECK(is_inserted) << source << " " << poll_id << " " << full_message_id; LOG_CHECK(is_inserted) << source << " " << poll_id << " " << full_message_id;
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (!(poll != nullptr)) return; CHECK(poll != nullptr);
if (!td_->auth_manager_->is_bot() && !is_local_poll_id(poll_id) && if (!td_->auth_manager_->is_bot() && !is_local_poll_id(poll_id) &&
!(poll->is_closed && poll->is_updated_after_close)) { !(poll->is_closed && poll->is_updated_after_close)) {
update_poll_timeout_.add_timeout_in(poll_id.get(), 0); update_poll_timeout_.add_timeout_in(poll_id.get(), 0);
@ -659,9 +641,7 @@ void PollManager::register_poll(PollId poll_id, FullMessageId full_message_id, c
} }
void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id, const char *source) { void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id, const char *source) {
if (!(have_poll(poll_id))) { CHECK(have_poll(poll_id));
return;
}
if (full_message_id.get_message_id().is_scheduled()) { if (full_message_id.get_message_id().is_scheduled()) {
return; return;
} }
@ -671,10 +651,7 @@ void PollManager::unregister_poll(PollId poll_id, FullMessageId full_message_id,
LOG(INFO) << "Unregister " << poll_id << " from " << full_message_id << " from " << source; LOG(INFO) << "Unregister " << poll_id << " from " << full_message_id << " from " << source;
auto &message_ids = poll_messages_[poll_id]; auto &message_ids = poll_messages_[poll_id];
auto is_deleted = message_ids.erase(full_message_id) > 0; auto is_deleted = message_ids.erase(full_message_id) > 0;
if (!is_deleted) { LOG_CHECK(is_deleted) << source << " " << poll_id << " " << full_message_id;
LOG(DEBUG) << "tried to unregister already deleted poll. " << source << " " << poll_id << " " << full_message_id;
return;
}
if (message_ids.empty()) { if (message_ids.empty()) {
poll_messages_.erase(poll_id); poll_messages_.erase(poll_id);
update_poll_timeout_.cancel_timeout(poll_id.get()); update_poll_timeout_.cancel_timeout(poll_id.get());
@ -714,7 +691,7 @@ void PollManager::set_poll_answer(PollId poll_id, FullMessageId full_message_id,
} }
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (!(poll != nullptr)) return promise.set_error(Status::Error(400, "Poll can't be answered")); CHECK(poll != nullptr);
if (poll->is_closed) { if (poll->is_closed) {
return promise.set_error(Status::Error(400, "Can't answer closed poll")); return promise.set_error(Status::Error(400, "Can't answer closed poll"));
} }
@ -963,7 +940,7 @@ void PollManager::get_poll_voters(PollId poll_id, FullMessageId full_message_id,
} }
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (!(poll != nullptr)) return promise.set_error(Status::Error(400, "Poll results can't be received")); CHECK(poll != nullptr);
if (option_id < 0 || static_cast<size_t>(option_id) >= poll->options.size()) { if (option_id < 0 || static_cast<size_t>(option_id) >= poll->options.size()) {
return promise.set_error(Status::Error(400, "Invalid option ID specified")); return promise.set_error(Status::Error(400, "Invalid option ID specified"));
} }
@ -1013,7 +990,7 @@ void PollManager::get_poll_voters(PollId poll_id, FullMessageId full_message_id,
void PollManager::on_get_poll_voters(PollId poll_id, int32 option_id, string offset, int32 limit, void PollManager::on_get_poll_voters(PollId poll_id, int32 option_id, string offset, int32 limit,
Result<tl_object_ptr<telegram_api::messages_votesList>> &&result) { Result<tl_object_ptr<telegram_api::messages_votesList>> &&result) {
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (!(poll != nullptr)) return; CHECK(poll != nullptr);
if (option_id < 0 || static_cast<size_t>(option_id) >= poll->options.size()) { if (option_id < 0 || static_cast<size_t>(option_id) >= poll->options.size()) {
LOG(ERROR) << "Can't process voters for option " << option_id << " in " << poll_id << ", because it has only " LOG(ERROR) << "Can't process voters for option " << option_id << " in " << poll_id << ", because it has only "
<< poll->options.size() << " options"; << poll->options.size() << " options";
@ -1107,10 +1084,7 @@ void PollManager::stop_poll(PollId poll_id, FullMessageId full_message_id, uniqu
return; return;
} }
auto poll = get_poll_editable(poll_id); auto poll = get_poll_editable(poll_id);
if (!(poll != nullptr)) { CHECK(poll != nullptr);
promise.set_value(Unit());
return;
}
if (poll->is_closed) { if (poll->is_closed) {
promise.set_value(Unit()); promise.set_value(Unit());
return; return;
@ -1163,7 +1137,7 @@ void PollManager::do_stop_poll(PollId poll_id, FullMessageId full_message_id, un
void PollManager::stop_local_poll(PollId poll_id) { void PollManager::stop_local_poll(PollId poll_id) {
CHECK(is_local_poll_id(poll_id)); CHECK(is_local_poll_id(poll_id));
auto poll = get_poll_editable(poll_id); auto poll = get_poll_editable(poll_id);
if (!(poll != nullptr)) return; CHECK(poll != nullptr);
if (poll->is_closed) { if (poll->is_closed) {
return; return;
} }
@ -1184,12 +1158,8 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
} }
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (poll == nullptr) { CHECK(poll != nullptr);
return;
}
if (poll->is_closed && poll->is_updated_after_close) { if (poll->is_closed && poll->is_updated_after_close) {
return; return;
} }
@ -1203,13 +1173,7 @@ void PollManager::on_update_poll_timeout(PollId poll_id) {
return; return;
} }
auto full_message_id_set = std::move(it->second); auto full_message_id = *it->second.begin();
if (full_message_id_set.empty()) {
return;
}
auto full_message_id = *full_message_id_set.begin();
LOG(INFO) << "Fetching results of " << poll_id << " from " << full_message_id; LOG(INFO) << "Fetching results of " << poll_id << " from " << full_message_id;
auto query_promise = PromiseCreator::lambda([poll_id, generation = current_generation_, actor_id = actor_id(this)]( auto query_promise = PromiseCreator::lambda([poll_id, generation = current_generation_, actor_id = actor_id(this)](
Result<tl_object_ptr<telegram_api::Updates>> &&result) { Result<tl_object_ptr<telegram_api::Updates>> &&result) {
@ -1226,7 +1190,7 @@ void PollManager::on_close_poll_timeout(PollId poll_id) {
} }
auto poll = get_poll_editable(poll_id); auto poll = get_poll_editable(poll_id);
if (!(poll != nullptr)) return; CHECK(poll != nullptr);
if (poll->is_closed || poll->close_date == 0) { if (poll->is_closed || poll->close_date == 0) {
return; return;
} }
@ -1250,7 +1214,7 @@ void PollManager::on_close_poll_timeout(PollId poll_id) {
void PollManager::on_get_poll_results(PollId poll_id, uint64 generation, void PollManager::on_get_poll_results(PollId poll_id, uint64 generation,
Result<tl_object_ptr<telegram_api::Updates>> result) { Result<tl_object_ptr<telegram_api::Updates>> result) {
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (!(poll != nullptr)) return; CHECK(poll != nullptr);
if (result.is_error()) { if (result.is_error()) {
if (!(poll->is_closed && poll->is_updated_after_close) && !G()->close_flag() && !td_->auth_manager_->is_bot()) { if (!(poll->is_closed && poll->is_updated_after_close) && !G()->close_flag() && !td_->auth_manager_->is_bot()) {
auto timeout = get_polling_timeout(); auto timeout = get_polling_timeout();
@ -1302,7 +1266,7 @@ PollId PollManager::dup_poll(PollId poll_id) {
bool PollManager::has_input_media(PollId poll_id) const { bool PollManager::has_input_media(PollId poll_id) const {
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (!(poll != nullptr)) return false; CHECK(poll != nullptr);
return !poll->is_quiz || poll->correct_option_id >= 0; return !poll->is_quiz || poll->correct_option_id >= 0;
} }
@ -1412,7 +1376,7 @@ PollId PollManager::on_get_poll(PollId poll_id, tl_object_ptr<telegram_api::poll
bool is_inserted = polls_.emplace(poll_id, std::move(p)).second; bool is_inserted = polls_.emplace(poll_id, std::move(p)).second;
CHECK(is_inserted); CHECK(is_inserted);
} }
if (!(poll != nullptr)) return PollId(); CHECK(poll != nullptr);
bool poll_server_is_closed = false; bool poll_server_is_closed = false;
if (poll_server != nullptr) { if (poll_server != nullptr) {
@ -1753,23 +1717,6 @@ void PollManager::on_binlog_events(vector<BinlogEvent> &&events) {
} }
} }
void PollManager::memory_cleanup() {
memory_cleanup(false);
}
void PollManager::memory_cleanup(bool full) {
polls_.clear();
polls_.rehash(0);
poll_messages_.clear();
poll_messages_.rehash(0);
poll_voters_.clear();
poll_voters_.rehash(0);
loaded_from_database_polls_.clear();
loaded_from_database_polls_.rehash(0);
being_closed_polls_.clear();
being_closed_polls_.rehash(0);
}
void PollManager::memory_stats(vector<string> &output) { void PollManager::memory_stats(vector<string> &output) {
output.push_back("\"polls_\":"); output.push_back(std::to_string(polls_.size())); output.push_back("\"polls_\":"); output.push_back(std::to_string(polls_.size()));
output.push_back(","); output.push_back(",");

View File

@ -43,8 +43,6 @@ class PollManager final : public Actor {
PollManager &operator=(PollManager &&) = delete; PollManager &operator=(PollManager &&) = delete;
~PollManager() final; ~PollManager() final;
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
static bool is_local_poll_id(PollId poll_id); static bool is_local_poll_id(PollId poll_id);
@ -147,8 +145,6 @@ class PollManager final : public Actor {
void start_up() final; void start_up() final;
void tear_down() final; void tear_down() final;
void memory_cleanup(bool full);
static void on_update_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int); static void on_update_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int);
static void on_close_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int); static void on_close_poll_timeout_callback(void *poll_manager_ptr, int64 poll_id_int);

View File

@ -128,9 +128,7 @@ void PollManager::store_poll(PollId poll_id, StorerT &storer) const {
td::store(poll_id.get(), storer); td::store(poll_id.get(), storer);
if (is_local_poll_id(poll_id)) { if (is_local_poll_id(poll_id)) {
auto poll = get_poll(poll_id); auto poll = get_poll(poll_id);
if (poll == nullptr) { CHECK(poll != nullptr);
return;
}
bool has_open_period = poll->open_period != 0; bool has_open_period = poll->open_period != 0;
bool has_close_date = poll->close_date != 0; bool has_close_date = poll->close_date != 0;
bool has_explanation = !poll->explanation.text.empty(); bool has_explanation = !poll->explanation.text.empty();

View File

@ -257,17 +257,13 @@ void MultiSequenceDispatcher::send_with_callback(NetQueryPtr query, ActorShared<
void MultiSequenceDispatcher::on_result() { void MultiSequenceDispatcher::on_result() {
auto it = dispatchers_.find(get_link_token()); auto it = dispatchers_.find(get_link_token());
if (it == dispatchers_.end()) { CHECK(it != dispatchers_.end());
return;
}
it->second.cnt_--; it->second.cnt_--;
} }
void MultiSequenceDispatcher::ready_to_close() { void MultiSequenceDispatcher::ready_to_close() {
auto it = dispatchers_.find(get_link_token()); auto it = dispatchers_.find(get_link_token());
if (it == dispatchers_.end()) { CHECK(it != dispatchers_.end());
return;
}
if (it->second.cnt_ == 0) { if (it->second.cnt_ == 0) {
LOG(DEBUG) << "Close SequenceDispatcher " << get_link_token(); LOG(DEBUG) << "Close SequenceDispatcher " << get_link_token();
dispatchers_.erase(it); dispatchers_.erase(it);

View File

@ -18,14 +18,6 @@ namespace td {
template <class T> template <class T>
class FastSetWithPosition { class FastSetWithPosition {
public: public:
std::vector<T> get_unchecked() const {
std::vector<T> res;
res.insert(res.end(), checked_.begin(), checked_.end());
res.insert(res.end(), not_checked_.begin(), not_checked_.end());
td::unique(res);
return res;
}
std::vector<T> get_some_elements() const { std::vector<T> get_some_elements() const {
std::vector<T> res; std::vector<T> res;
res.reserve(4); res.reserve(4);
@ -114,16 +106,6 @@ class FastSetWithPosition {
template <class T> template <class T>
class SetWithPosition { class SetWithPosition {
public: public:
std::vector<T> get_all_elements() const {
if (fast_) {
return fast_->get_unchecked();
}
if (has_value_) {
return {value_};
}
return {};
}
std::vector<T> get_some_elements() const { std::vector<T> get_some_elements() const {
if (fast_) { if (fast_) {
return fast_->get_some_elements(); return fast_->get_some_elements();

View File

@ -1401,9 +1401,7 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
CHECK(special_sticker_set.id_.is_valid()); CHECK(special_sticker_set.id_.is_valid());
auto sticker_set = get_sticker_set(special_sticker_set.id_); auto sticker_set = get_sticker_set(special_sticker_set.id_);
if (sticker_set == nullptr) { CHECK(sticker_set != nullptr);
return;
}
CHECK(sticker_set->was_loaded); CHECK(sticker_set->was_loaded);
if (type.type_ == SpecialStickerSetType::animated_emoji_click()) { if (type.type_ == SpecialStickerSetType::animated_emoji_click()) {
@ -1442,8 +1440,6 @@ void StickersManager::on_load_special_sticker_set(const SpecialStickerSetType &t
void StickersManager::tear_down() { void StickersManager::tear_down() {
parent_.reset(); parent_.reset();
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup();
} }
tl_object_ptr<td_api::MaskPoint> StickersManager::get_mask_point_object(int32 point) { tl_object_ptr<td_api::MaskPoint> StickersManager::get_mask_point_object(int32 point) {
@ -1705,17 +1701,9 @@ tl_object_ptr<td_api::sticker> StickersManager::get_sticker_object(FileId file_i
} }
auto it = stickers_.find(file_id); auto it = stickers_.find(file_id);
CHECK(it != stickers_.end());
if (it == stickers_.end() || it->second == nullptr) {
return nullptr;
}
auto sticker = it->second.get(); auto sticker = it->second.get();
CHECK(sticker != nullptr);
if (sticker == nullptr) {
return nullptr;
}
auto mask_position = sticker->point >= 0 auto mask_position = sticker->point >= 0
? make_tl_object<td_api::maskPosition>(get_mask_point_object(sticker->point), ? make_tl_object<td_api::maskPosition>(get_mask_point_object(sticker->point),
sticker->x_shift, sticker->y_shift, sticker->scale) sticker->x_shift, sticker->y_shift, sticker->scale)
@ -1778,9 +1766,7 @@ tl_object_ptr<td_api::DiceStickers> StickersManager::get_dice_stickers_object(co
} }
auto sticker_set = get_sticker_set(sticker_set_id); auto sticker_set = get_sticker_set(sticker_set_id);
if (sticker_set == nullptr) { CHECK(sticker_set != nullptr);
return nullptr;
}
if (!sticker_set->was_loaded) { if (!sticker_set->was_loaded) {
return nullptr; return nullptr;
} }
@ -2056,8 +2042,8 @@ std::pair<int64, FileId> StickersManager::on_get_sticker_document(
StickersManager::Sticker *StickersManager::get_sticker(FileId file_id) { StickersManager::Sticker *StickersManager::get_sticker(FileId file_id) {
auto sticker = stickers_.find(file_id); auto sticker = stickers_.find(file_id);
if (sticker == stickers_.end() || sticker->second == nullptr) { if (sticker == stickers_.end()) {
return make_unique<Sticker>().get(); return nullptr;
} }
CHECK(sticker->second->file_id == file_id); CHECK(sticker->second->file_id == file_id);
@ -2066,22 +2052,18 @@ StickersManager::Sticker *StickersManager::get_sticker(FileId file_id) {
const StickersManager::Sticker *StickersManager::get_sticker(FileId file_id) const { const StickersManager::Sticker *StickersManager::get_sticker(FileId file_id) const {
auto sticker = stickers_.find(file_id); auto sticker = stickers_.find(file_id);
if (sticker == stickers_.end()) {
if (sticker == stickers_.end() || return nullptr;
sticker->second == nullptr ||
sticker->second->file_id != file_id) {
return make_unique<Sticker>().get();
} }
CHECK(sticker->second->file_id == file_id);
return sticker->second.get(); return sticker->second.get();
} }
StickersManager::StickerSet *StickersManager::get_sticker_set(StickerSetId sticker_set_id) { StickersManager::StickerSet *StickersManager::get_sticker_set(StickerSetId sticker_set_id) {
auto sticker_set = sticker_sets_.find(sticker_set_id); auto sticker_set = sticker_sets_.find(sticker_set_id);
if (sticker_set == sticker_sets_.end()) {
if (sticker_set == sticker_sets_.end() || return nullptr;
sticker_set->second == nullptr) {
return make_unique<StickerSet>().get();
} }
return sticker_set->second.get(); return sticker_set->second.get();
@ -2090,7 +2072,7 @@ StickersManager::StickerSet *StickersManager::get_sticker_set(StickerSetId stick
const StickersManager::StickerSet *StickersManager::get_sticker_set(StickerSetId sticker_set_id) const { const StickersManager::StickerSet *StickersManager::get_sticker_set(StickerSetId sticker_set_id) const {
auto sticker_set = sticker_sets_.find(sticker_set_id); auto sticker_set = sticker_sets_.find(sticker_set_id);
if (sticker_set == sticker_sets_.end()) { if (sticker_set == sticker_sets_.end()) {
return make_unique<StickerSet>().get(); return nullptr;
} }
return sticker_set->second.get(); return sticker_set->second.get();
@ -2184,11 +2166,7 @@ void StickersManager::delete_sticker_thumbnail(FileId file_id) {
vector<FileId> StickersManager::get_sticker_file_ids(FileId file_id) const { vector<FileId> StickersManager::get_sticker_file_ids(FileId file_id) const {
vector<FileId> result; vector<FileId> result;
auto sticker = get_sticker(file_id); auto sticker = get_sticker(file_id);
CHECK(sticker != nullptr);
if (sticker == nullptr) {
return result;
}
result.push_back(file_id); result.push_back(file_id);
if (sticker->s_thumbnail.file_id.is_valid()) { if (sticker->s_thumbnail.file_id.is_valid()) {
result.push_back(sticker->s_thumbnail.file_id); result.push_back(sticker->s_thumbnail.file_id);
@ -2220,7 +2198,7 @@ void StickersManager::merge_stickers(FileId new_id, FileId old_id, bool can_dele
CHECK(old_ != nullptr); CHECK(old_ != nullptr);
auto new_it = stickers_.find(new_id); auto new_it = stickers_.find(new_id);
if (new_it == stickers_.end() || new_it->second == nullptr) { if (new_it == stickers_.end()) {
auto &old = stickers_[old_id]; auto &old = stickers_[old_id];
if (!can_delete_old) { if (!can_delete_old) {
dup_sticker(new_id, old_id); dup_sticker(new_id, old_id);
@ -2405,9 +2383,6 @@ bool StickersManager::has_input_media(FileId sticker_file_id, bool is_secret) co
auto file_view = td_->file_manager_->get_file_view(sticker_file_id); auto file_view = td_->file_manager_->get_file_view(sticker_file_id);
if (is_secret) { if (is_secret) {
const Sticker *sticker = get_sticker(sticker_file_id); const Sticker *sticker = get_sticker(sticker_file_id);
if (sticker == nullptr) {
return false;
}
CHECK(sticker != nullptr); CHECK(sticker != nullptr);
if (file_view.is_encrypted_secret()) { if (file_view.is_encrypted_secret()) {
if (!file_view.encryption_key().empty() && file_view.has_remote_location() && if (!file_view.encryption_key().empty() && file_view.has_remote_location() &&
@ -2442,11 +2417,7 @@ SecretInputMedia StickersManager::get_secret_input_media(FileId sticker_file_id,
tl_object_ptr<telegram_api::InputEncryptedFile> input_file, tl_object_ptr<telegram_api::InputEncryptedFile> input_file,
BufferSlice thumbnail) const { BufferSlice thumbnail) const {
const Sticker *sticker = get_sticker(sticker_file_id); const Sticker *sticker = get_sticker(sticker_file_id);
CHECK(sticker != nullptr);
if (sticker == nullptr) {
return {};
}
auto file_view = td_->file_manager_->get_file_view(sticker_file_id); auto file_view = td_->file_manager_->get_file_view(sticker_file_id);
if (file_view.is_encrypted_secret()) { if (file_view.is_encrypted_secret()) {
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
@ -4041,13 +4012,7 @@ void StickersManager::unregister_dice(const string &emoji, int32 value, FullMess
<< source; << source;
auto &message_ids = dice_messages_[emoji]; auto &message_ids = dice_messages_[emoji];
auto is_deleted = message_ids.erase(full_message_id) > 0; auto is_deleted = message_ids.erase(full_message_id) > 0;
// Start custom-patches
if (is_deleted) {
// End custom-patches
LOG_CHECK(is_deleted) << source << " " << emoji << " " << value << " " << full_message_id; LOG_CHECK(is_deleted) << source << " " << emoji << " " << value << " " << full_message_id;
// Start custom-patches
}
// End custom-patches
if (message_ids.empty()) { if (message_ids.empty()) {
dice_messages_.erase(emoji); dice_messages_.erase(emoji);
@ -6009,9 +5974,7 @@ int64 StickersManager::get_recent_stickers_hash(const vector<FileId> &sticker_id
numbers.reserve(sticker_ids.size()); numbers.reserve(sticker_ids.size());
for (auto sticker_id : sticker_ids) { for (auto sticker_id : sticker_ids) {
auto sticker = get_sticker(sticker_id); auto sticker = get_sticker(sticker_id);
if (sticker == nullptr) { CHECK(sticker != nullptr);
continue;
}
auto file_view = td_->file_manager_->get_file_view(sticker_id); auto file_view = td_->file_manager_->get_file_view(sticker_id);
CHECK(file_view.has_remote_location()); CHECK(file_view.has_remote_location());
if (!file_view.remote_location().is_document()) { if (!file_view.remote_location().is_document()) {
@ -7156,24 +7119,6 @@ void StickersManager::get_current_state(vector<td_api::object_ptr<td_api::Update
} }
} }
void StickersManager::memory_cleanup() {
stickers_.clear();
stickers_.rehash(0);
sticker_sets_.clear();
sticker_sets_.rehash(0);
short_name_to_sticker_set_id_.clear();
short_name_to_sticker_set_id_.rehash(0);
attached_sticker_sets_.clear();
attached_sticker_sets_.rehash(0);
found_stickers_.clear();
found_stickers_.rehash(0);
found_sticker_sets_.clear();
found_sticker_sets_.rehash(0);
special_sticker_sets_.clear();
special_sticker_sets_.rehash(0);
dice_messages_.clear();
dice_messages_.rehash(0);
}
void StickersManager::memory_stats(vector<string> &output) { void StickersManager::memory_stats(vector<string> &output) {
output.push_back("\"found_stickers_\":"); output.push_back(std::to_string(found_stickers_.size())); output.push_back("\"found_stickers_\":"); output.push_back(std::to_string(found_stickers_.size()));
output.push_back(","); output.push_back(",");

View File

@ -41,8 +41,6 @@ class StickersManager final : public Actor {
public: public:
static constexpr int64 GREAT_MINDS_SET_ID = 1842540969984001; static constexpr int64 GREAT_MINDS_SET_ID = 1842540969984001;
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
static vector<StickerSetId> convert_sticker_set_ids(const vector<int64> &sticker_set_ids); static vector<StickerSetId> convert_sticker_set_ids(const vector<int64> &sticker_set_ids);

View File

@ -24,9 +24,7 @@ namespace td {
template <class StorerT> template <class StorerT>
void StickersManager::store_sticker(FileId file_id, bool in_sticker_set, StorerT &storer, const char *source) const { void StickersManager::store_sticker(FileId file_id, bool in_sticker_set, StorerT &storer, const char *source) const {
auto it = stickers_.find(file_id); auto it = stickers_.find(file_id);
if (it == stickers_.end() || it->second == nullptr) { LOG_CHECK(it != stickers_.end()) << file_id << ' ' << in_sticker_set << ' ' << source;
return;
}
const Sticker *sticker = it->second.get(); const Sticker *sticker = it->second.get();
bool has_sticker_set_access_hash = sticker->set_id.is_valid() && !in_sticker_set; bool has_sticker_set_access_hash = sticker->set_id.is_valid() && !in_sticker_set;
bool has_minithumbnail = !sticker->minithumbnail.empty(); bool has_minithumbnail = !sticker->minithumbnail.empty();
@ -41,11 +39,10 @@ void StickersManager::store_sticker(FileId file_id, bool in_sticker_set, StorerT
store(sticker->set_id.get(), storer); store(sticker->set_id.get(), storer);
if (has_sticker_set_access_hash) { if (has_sticker_set_access_hash) {
auto sticker_set = get_sticker_set(sticker->set_id); auto sticker_set = get_sticker_set(sticker->set_id);
if (sticker_set != nullptr) { CHECK(sticker_set != nullptr);
store(sticker_set->access_hash, storer); store(sticker_set->access_hash, storer);
} }
} }
}
store(sticker->alt, storer); store(sticker->alt, storer);
store(sticker->dimensions, storer); store(sticker->dimensions, storer);
store(sticker->s_thumbnail, storer); store(sticker->s_thumbnail, storer);
@ -188,9 +185,7 @@ void StickersManager::store_sticker_set(const StickerSet *sticker_set, bool with
template <class ParserT> template <class ParserT>
void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser) { void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser) {
if (sticker_set == nullptr) { CHECK(sticker_set != nullptr);
return;
}
CHECK(!sticker_set->was_loaded); CHECK(!sticker_set->was_loaded);
bool was_inited = sticker_set->is_inited; bool was_inited = sticker_set->is_inited;
bool is_installed; bool is_installed;
@ -302,9 +297,7 @@ void StickersManager::parse_sticker_set(StickerSet *sticker_set, ParserT &parser
sticker_set->sticker_ids.push_back(sticker_id); sticker_set->sticker_ids.push_back(sticker_id);
Sticker *sticker = get_sticker(sticker_id); Sticker *sticker = get_sticker(sticker_id);
if (sticker == nullptr) { CHECK(sticker != nullptr);
return;
}
if (sticker->set_id != sticker_set->id) { if (sticker->set_id != sticker_set->id) {
LOG_IF(ERROR, sticker->set_id.is_valid()) << "Sticker " << sticker_id << " set_id has changed"; LOG_IF(ERROR, sticker->set_id.is_valid()) << "Sticker " << sticker_id << " set_id has changed";
sticker->set_id = sticker_set->id; sticker->set_id = sticker_set->id;
@ -339,9 +332,7 @@ template <class StorerT>
void StickersManager::store_sticker_set_id(StickerSetId sticker_set_id, StorerT &storer) const { void StickersManager::store_sticker_set_id(StickerSetId sticker_set_id, StorerT &storer) const {
CHECK(sticker_set_id.is_valid()); CHECK(sticker_set_id.is_valid());
const StickerSet *sticker_set = get_sticker_set(sticker_set_id); const StickerSet *sticker_set = get_sticker_set(sticker_set_id);
if (sticker_set == nullptr) { CHECK(sticker_set != nullptr);
return;
}
store(sticker_set_id.get(), storer); store(sticker_set_id.get(), storer);
store(sticker_set->access_hash, storer); store(sticker_set->access_hash, storer);
} }

View File

@ -152,9 +152,6 @@ namespace td {
int VERBOSITY_NAME(td_init) = VERBOSITY_NAME(DEBUG) + 3; int VERBOSITY_NAME(td_init) = VERBOSITY_NAME(DEBUG) + 3;
int VERBOSITY_NAME(td_requests) = VERBOSITY_NAME(INFO); int VERBOSITY_NAME(td_requests) = VERBOSITY_NAME(INFO);
int VERBOSITY_NAME(messages) = VERBOSITY_NAME(INFO);
int VERBOSITY_NAME(postponed_pts_update) = VERBOSITY_NAME(DEBUG);
int VERBOSITY_NAME(add_pending_update) = VERBOSITY_NAME(DEBUG);
void Td::ResultHandler::set_td(Td *new_td) { void Td::ResultHandler::set_td(Td *new_td) {
CHECK(td == nullptr); CHECK(td == nullptr);
@ -3107,7 +3104,6 @@ bool Td::is_preauthentication_request(int32 id) {
case td_api::getStorageStatisticsFast::ID: case td_api::getStorageStatisticsFast::ID:
case td_api::getDatabaseStatistics::ID: case td_api::getDatabaseStatistics::ID:
case td_api::getMemoryStatistics::ID: case td_api::getMemoryStatistics::ID:
case td_api::optimizeMemory::ID:
case td_api::setNetworkType::ID: case td_api::setNetworkType::ID:
case td_api::getNetworkStatistics::ID: case td_api::getNetworkStatistics::ID:
case td_api::addNetworkStatistics::ID: case td_api::addNetworkStatistics::ID:
@ -4198,10 +4194,6 @@ void Td::init_file_manager() {
send_closure(G()->storage_manager(), &StorageManager::on_new_file, size, real_size, cnt); send_closure(G()->storage_manager(), &StorageManager::on_new_file, size, real_size, cnt);
} }
void destroy_file_source(FileId file_id) final {
td_->file_reference_manager_->memory_cleanup(file_id);
}
void on_file_updated(FileId file_id) final { void on_file_updated(FileId file_id) final {
send_closure(G()->td(), &Td::send_update, send_closure(G()->td(), &Td::send_update,
make_tl_object<td_api::updateFile>(td_->file_manager_->get_file_object(file_id))); make_tl_object<td_api::updateFile>(td_->file_manager_->get_file_object(file_id)));
@ -5052,18 +5044,6 @@ void Td::on_request(uint64 id, const td_api::getFile &request) {
send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(FileId(request.file_id_, 0))); send_closure(actor_id(this), &Td::send_result, id, file_manager_->get_file_object(FileId(request.file_id_, 0)));
} }
void Td::on_request(uint64 id, const td_api::getChannelDifference &request) {
auto result = messages_manager_->run_get_channel_difference_request(request.channel_difference_id_);
if (result) {
send_closure(actor_id(this), &Td::send_result, id,
td_api::make_object<td_api::ok>());
} else {
send_closure(actor_id(this), &Td::send_result, id,
td_api::make_object<td_api::error>(
400, "Channel diffence identifier already executed or nonexistent"));
}
}
void Td::on_request(uint64 id, td_api::getRemoteFile &request) { void Td::on_request(uint64 id, td_api::getRemoteFile &request) {
CLEAN_INPUT_STRING(request.remote_file_id_); CLEAN_INPUT_STRING(request.remote_file_id_);
auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_); auto file_type = request.file_type_ == nullptr ? FileType::Temp : get_file_type(*request.file_type_);
@ -5122,18 +5102,6 @@ void Td::on_request(uint64 id, td_api::getMemoryStatistics &request) {
memory_manager_->get_memory_stats(request.full_, std::move(query_promise)); memory_manager_->get_memory_stats(request.full_, std::move(query_promise));
} }
void Td::on_request(uint64 id, td_api::optimizeMemory &request) {
CREATE_REQUEST_PROMISE();
auto query_promise = PromiseCreator::lambda([promise = std::move(promise)](Result<Unit> result) mutable {
if (result.is_error()) {
promise.set_error(result.move_as_error());
} else {
promise.set_value(make_tl_object<td_api::ok>());
}
});
memory_manager_->clean_memory(request.full_, std::move(query_promise));
}
void Td::on_request(uint64 id, td_api::optimizeStorage &request) { void Td::on_request(uint64 id, td_api::optimizeStorage &request) {
std::vector<FileType> file_types; std::vector<FileType> file_types;
@ -7547,15 +7515,6 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
if (set_boolean_option("disable_group_calls")) { if (set_boolean_option("disable_group_calls")) {
return; return;
} }
if (set_integer_option("delete_file_reference_after_seconds")) {
return;
}
if (set_integer_option("delete_user_reference_after_seconds")) {
return;
}
if (set_integer_option("delete_chat_reference_after_seconds")) {
return;
}
// End custom-patches // End custom-patches
if (set_boolean_option("disable_persistent_network_statistics")) { if (set_boolean_option("disable_persistent_network_statistics")) {
return; return;
@ -7570,23 +7529,6 @@ void Td::on_request(uint64 id, td_api::setOption &request) {
return; return;
} }
break; break;
case 'e':
if (set_boolean_option("experiment_enable_file_reference_cleanup")) {
return;
}
if (set_boolean_option("experiment_debug_file_reference_cleanup")) {
return;
}
if (set_boolean_option("experiment_enable_chat_access_hash_cleanup")) {
return;
}
if (set_boolean_option("experiment_old_postponed_pts_updates_behavior")) {
return;
}
if (set_boolean_option("enable_reactive_channel_difference")) {
return;
}
break;
case 'i': case 'i':
if (set_boolean_option("ignore_background_updates")) { if (set_boolean_option("ignore_background_updates")) {
return; return;

View File

@ -86,9 +86,6 @@ class WebPagesManager;
extern int VERBOSITY_NAME(td_init); extern int VERBOSITY_NAME(td_init);
extern int VERBOSITY_NAME(td_requests); extern int VERBOSITY_NAME(td_requests);
extern int VERBOSITY_NAME(messages);
extern int VERBOSITY_NAME(postponed_pts_update);
extern int VERBOSITY_NAME(add_pending_update);
// Td may start closing after explicit "close" or "destroy" query. // Td may start closing after explicit "close" or "destroy" query.
// Or it may start closing by itself, because authorization is lost. // Or it may start closing by itself, because authorization is lost.
@ -543,8 +540,6 @@ class Td final : public Actor {
void on_request(uint64 id, const td_api::getFile &request); void on_request(uint64 id, const td_api::getFile &request);
void on_request(uint64 id, const td_api::getChannelDifference &request);
void on_request(uint64 id, td_api::getRemoteFile &request); void on_request(uint64 id, td_api::getRemoteFile &request);
void on_request(uint64 id, td_api::getStorageStatistics &request); void on_request(uint64 id, td_api::getStorageStatistics &request);
@ -555,8 +550,6 @@ class Td final : public Actor {
void on_request(uint64 id, td_api::getMemoryStatistics &request); void on_request(uint64 id, td_api::getMemoryStatistics &request);
void on_request(uint64 id, td_api::optimizeMemory &request);
void on_request(uint64 id, td_api::optimizeStorage &request); void on_request(uint64 id, td_api::optimizeStorage &request);
void on_request(uint64 id, td_api::getNetworkStatistics &request); void on_request(uint64 id, td_api::getNetworkStatistics &request);

View File

@ -11,7 +11,6 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include <ctime>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
@ -19,13 +18,13 @@ namespace td {
class UserId { class UserId {
int64 id = 0; int64 id = 0;
int64 time_ = INT64_MAX;
public: public:
static constexpr int64 MAX_USER_ID = (1ll << 40) - 1; static constexpr int64 MAX_USER_ID = (1ll << 40) - 1;
UserId() = default;
explicit UserId(int64 user_id) : id(user_id) { explicit UserId(int64 user_id) : id(user_id) {
set_time();
} }
template <class T, typename = std::enable_if_t<std::is_convertible<T, int64>::value>> template <class T, typename = std::enable_if_t<std::is_convertible<T, int64>::value>>
UserId(T user_id) = delete; UserId(T user_id) = delete;
@ -56,18 +55,6 @@ class UserId {
return id; return id;
} }
void set_time() {
time_ = std::time(nullptr);
}
int64 get_time() const {
return time_;
}
void reset_time() {
time_ = INT64_MAX;
}
bool operator==(const UserId &other) const { bool operator==(const UserId &other) const {
return id == other.id; return id == other.id;
} }

View File

@ -14,7 +14,6 @@
#include "td/telegram/telegram_api.h" #include "td/telegram/telegram_api.h"
#include "td/telegram/ConfigShared.h" #include "td/telegram/ConfigShared.h"
#include "td/telegram/Td.h"
#include "td/utils/logging.h" #include "td/utils/logging.h"
#include "td/utils/misc.h" #include "td/utils/misc.h"
#include "td/utils/Status.h" #include "td/utils/Status.h"
@ -26,9 +25,7 @@ VideoNotesManager::VideoNotesManager(Td *td) : td_(td) {
int32 VideoNotesManager::get_video_note_duration(FileId file_id) const { int32 VideoNotesManager::get_video_note_duration(FileId file_id) const {
auto it = video_notes_.find(file_id); auto it = video_notes_.find(file_id);
if (it == video_notes_.end() || it->second == nullptr) { CHECK(it != video_notes_.end());
return 0;
}
return it->second->duration; return it->second->duration;
} }
@ -38,13 +35,8 @@ tl_object_ptr<td_api::videoNote> VideoNotesManager::get_video_note_object(FileId
} }
auto it = video_notes_.find(file_id); auto it = video_notes_.find(file_id);
if (it == video_notes_.end()) { CHECK(it != video_notes_.end());
return nullptr;
}
auto video_note = it->second.get(); auto video_note = it->second.get();
if (video_note == nullptr) {
return nullptr;
}
return make_tl_object<td_api::videoNote>( return make_tl_object<td_api::videoNote>(
video_note->duration, video_note->dimensions.width, get_minithumbnail_object(video_note->minithumbnail), video_note->duration, video_note->dimensions.width, get_minithumbnail_object(video_note->minithumbnail),
get_thumbnail_object(td_->file_manager_.get(), video_note->thumbnail, PhotoFormat::Jpeg), get_thumbnail_object(td_->file_manager_.get(), video_note->thumbnail, PhotoFormat::Jpeg),
@ -85,37 +77,29 @@ FileId VideoNotesManager::on_get_video_note(unique_ptr<VideoNote> new_video_note
const VideoNotesManager::VideoNote *VideoNotesManager::get_video_note(FileId file_id) const { const VideoNotesManager::VideoNote *VideoNotesManager::get_video_note(FileId file_id) const {
auto video_note = video_notes_.find(file_id); auto video_note = video_notes_.find(file_id);
if (video_note == video_notes_.end()) {
if (video_note == video_notes_.end() || return nullptr;
video_note->second == nullptr ||
video_note->second->file_id != file_id) {
return make_unique<VideoNote>().get();
} }
CHECK(video_note->second->file_id == file_id);
return video_note->second.get(); return video_note->second.get();
} }
FileId VideoNotesManager::get_video_note_thumbnail_file_id(FileId file_id) const { FileId VideoNotesManager::get_video_note_thumbnail_file_id(FileId file_id) const {
auto video_note = get_video_note(file_id); auto video_note = get_video_note(file_id);
if (video_note == nullptr) { CHECK(video_note != nullptr);
return FileId();
}
return video_note->thumbnail.file_id; return video_note->thumbnail.file_id;
} }
void VideoNotesManager::delete_video_note_thumbnail(FileId file_id) { void VideoNotesManager::delete_video_note_thumbnail(FileId file_id) {
auto &video_note = video_notes_[file_id]; auto &video_note = video_notes_[file_id];
if (video_note == nullptr) { CHECK(video_note != nullptr);
return;
}
video_note->thumbnail = PhotoSize(); video_note->thumbnail = PhotoSize();
} }
FileId VideoNotesManager::dup_video_note(FileId new_id, FileId old_id) { FileId VideoNotesManager::dup_video_note(FileId new_id, FileId old_id) {
const VideoNote *old_video_note = get_video_note(old_id); const VideoNote *old_video_note = get_video_note(old_id);
if (old_video_note == nullptr) { CHECK(old_video_note != nullptr);
return FileId();
}
auto &new_video_note = video_notes_[new_id]; auto &new_video_note = video_notes_[new_id];
CHECK(!new_video_note); CHECK(!new_video_note);
new_video_note = make_unique<VideoNote>(*old_video_note); new_video_note = make_unique<VideoNote>(*old_video_note);
@ -133,7 +117,7 @@ void VideoNotesManager::merge_video_notes(FileId new_id, FileId old_id, bool can
CHECK(old_ != nullptr); CHECK(old_ != nullptr);
auto new_it = video_notes_.find(new_id); auto new_it = video_notes_.find(new_id);
if (new_it == video_notes_.end() || new_it->second == nullptr) { if (new_it == video_notes_.end()) {
auto &old = video_notes_[old_id]; auto &old = video_notes_[old_id];
if (!can_delete_old) { if (!can_delete_old) {
dup_video_note(new_id, old_id); dup_video_note(new_id, old_id);
@ -219,9 +203,7 @@ tl_object_ptr<telegram_api::InputMedia> VideoNotesManager::get_input_media(
if (input_file != nullptr) { if (input_file != nullptr) {
const VideoNote *video_note = get_video_note(file_id); const VideoNote *video_note = get_video_note(file_id);
if (video_note == nullptr) { CHECK(video_note != nullptr);
return nullptr;
}
vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes; vector<tl_object_ptr<telegram_api::DocumentAttribute>> attributes;
attributes.push_back(make_tl_object<telegram_api::documentAttributeVideo>( attributes.push_back(make_tl_object<telegram_api::documentAttributeVideo>(
@ -242,10 +224,6 @@ tl_object_ptr<telegram_api::InputMedia> VideoNotesManager::get_input_media(
return nullptr; return nullptr;
} }
void VideoNotesManager::memory_cleanup() {
video_notes_.clear();
video_notes_.rehash(0);
}
void VideoNotesManager::memory_stats(vector<string> &output) { void VideoNotesManager::memory_stats(vector<string> &output) {
output.push_back("\"video_notes_\":"); output.push_back(std::to_string(video_notes_.size())); output.push_back("\"video_notes_\":"); output.push_back(std::to_string(video_notes_.size()));
} }

View File

@ -26,8 +26,6 @@ class VideoNotesManager {
public: public:
explicit VideoNotesManager(Td *td); explicit VideoNotesManager(Td *td);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
int32 get_video_note_duration(FileId file_id) const; int32 get_video_note_duration(FileId file_id) const;

View File

@ -20,9 +20,7 @@ namespace td {
template <class StorerT> template <class StorerT>
void VideoNotesManager::store_video_note(FileId file_id, StorerT &storer) const { void VideoNotesManager::store_video_note(FileId file_id, StorerT &storer) const {
auto it = video_notes_.find(file_id); auto it = video_notes_.find(file_id);
if (it == video_notes_.end() || it->second == nullptr) { CHECK(it != video_notes_.end());
return;
}
const VideoNote *video_note = it->second.get(); const VideoNote *video_note = it->second.get();
store(video_note->duration, storer); store(video_note->duration, storer);
store(video_note->dimensions, storer); store(video_note->dimensions, storer);
@ -50,4 +48,5 @@ FileId VideoNotesManager::parse_video_note(ParserT &parser) {
} }
return on_get_video_note(std::move(video_note), false); return on_get_video_note(std::move(video_note), false);
} }
} // namespace td } // namespace td

View File

@ -25,9 +25,7 @@ VideosManager::VideosManager(Td *td) : td_(td) {
int32 VideosManager::get_video_duration(FileId file_id) const { int32 VideosManager::get_video_duration(FileId file_id) const {
auto it = videos_.find(file_id); auto it = videos_.find(file_id);
if (it == videos_.end() || it->second == nullptr) { CHECK(it != videos_.end());
return 0;
}
return it->second->duration; return it->second->duration;
} }
@ -37,13 +35,9 @@ tl_object_ptr<td_api::video> VideosManager::get_video_object(FileId file_id) con
} }
auto it = videos_.find(file_id); auto it = videos_.find(file_id);
if (it == videos_.end()) { CHECK(it != videos_.end());
return nullptr;
}
auto video = it->second.get(); auto video = it->second.get();
if (video == nullptr) { CHECK(video != nullptr);
return nullptr;
}
auto thumbnail = video->animated_thumbnail.file_id.is_valid() auto thumbnail = video->animated_thumbnail.file_id.is_valid()
? get_thumbnail_object(td_->file_manager_.get(), video->animated_thumbnail, PhotoFormat::Mpeg4) ? get_thumbnail_object(td_->file_manager_.get(), video->animated_thumbnail, PhotoFormat::Mpeg4)
: get_thumbnail_object(td_->file_manager_.get(), video->thumbnail, PhotoFormat::Jpeg); : get_thumbnail_object(td_->file_manager_.get(), video->thumbnail, PhotoFormat::Jpeg);
@ -112,37 +106,29 @@ FileId VideosManager::on_get_video(unique_ptr<Video> new_video, bool replace) {
const VideosManager::Video *VideosManager::get_video(FileId file_id) const { const VideosManager::Video *VideosManager::get_video(FileId file_id) const {
auto video = videos_.find(file_id); auto video = videos_.find(file_id);
if (video == videos_.end()) {
if (video == videos_.end() || return nullptr;
video->second == nullptr ||
video->second->file_id != file_id) {
return make_unique<Video>().get();
} }
CHECK(video->second->file_id == file_id);
return video->second.get(); return video->second.get();
} }
FileId VideosManager::get_video_thumbnail_file_id(FileId file_id) const { FileId VideosManager::get_video_thumbnail_file_id(FileId file_id) const {
auto video = get_video(file_id); auto video = get_video(file_id);
if (video == nullptr) { CHECK(video != nullptr);
return FileId();
}
return video->thumbnail.file_id; return video->thumbnail.file_id;
} }
FileId VideosManager::get_video_animated_thumbnail_file_id(FileId file_id) const { FileId VideosManager::get_video_animated_thumbnail_file_id(FileId file_id) const {
auto video = get_video(file_id); auto video = get_video(file_id);
if (video == nullptr) { CHECK(video != nullptr);
return FileId();
}
return video->animated_thumbnail.file_id; return video->animated_thumbnail.file_id;
} }
void VideosManager::delete_video_thumbnail(FileId file_id) { void VideosManager::delete_video_thumbnail(FileId file_id) {
auto &video = videos_[file_id]; auto &video = videos_[file_id];
if (video == nullptr) { CHECK(video != nullptr);
return;
}
video->thumbnail = PhotoSize(); video->thumbnail = PhotoSize();
video->animated_thumbnail = AnimationSize(); video->animated_thumbnail = AnimationSize();
} }
@ -168,7 +154,7 @@ void VideosManager::merge_videos(FileId new_id, FileId old_id, bool can_delete_o
CHECK(old_ != nullptr); CHECK(old_ != nullptr);
auto new_it = videos_.find(new_id); auto new_it = videos_.find(new_id);
if (new_it == videos_.end() || new_it->second == nullptr) { if (new_it == videos_.end()) {
auto &old = videos_[old_id]; auto &old = videos_[old_id];
if (!can_delete_old) { if (!can_delete_old) {
dup_video(new_id, old_id); dup_video(new_id, old_id);
@ -316,10 +302,7 @@ string VideosManager::get_video_search_text(FileId file_id) const {
CHECK(video != nullptr); CHECK(video != nullptr);
return video->file_name; return video->file_name;
} }
void VideosManager::memory_cleanup() {
videos_.clear();
videos_.rehash(0);
}
void VideosManager::memory_stats(vector<string> &output) { void VideosManager::memory_stats(vector<string> &output) {
output.push_back("\"videos_\":"); output.push_back(std::to_string(videos_.size())); output.push_back("\"videos_\":"); output.push_back(std::to_string(videos_.size()));
} }

View File

@ -26,8 +26,6 @@ class VideosManager {
public: public:
explicit VideosManager(Td *td); explicit VideosManager(Td *td);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
int32 get_video_duration(FileId file_id) const; int32 get_video_duration(FileId file_id) const;

View File

@ -20,9 +20,7 @@ namespace td {
template <class StorerT> template <class StorerT>
void VideosManager::store_video(FileId file_id, StorerT &storer) const { void VideosManager::store_video(FileId file_id, StorerT &storer) const {
auto it = videos_.find(file_id); auto it = videos_.find(file_id);
if (it == videos_.end() || it->second == nullptr) { CHECK(it != videos_.end());
return;
}
const Video *video = it->second.get(); const Video *video = it->second.get();
bool has_animated_thumbnail = video->animated_thumbnail.file_id.is_valid(); bool has_animated_thumbnail = video->animated_thumbnail.file_id.is_valid();
BEGIN_STORE_FLAGS(); BEGIN_STORE_FLAGS();

View File

@ -24,9 +24,7 @@ VoiceNotesManager::VoiceNotesManager(Td *td) : td_(td) {
int32 VoiceNotesManager::get_voice_note_duration(FileId file_id) const { int32 VoiceNotesManager::get_voice_note_duration(FileId file_id) const {
auto it = voice_notes_.find(file_id); auto it = voice_notes_.find(file_id);
if (it == voice_notes_.end() || it->second == nullptr) { CHECK(it != voice_notes_.end());
return 0;
}
return it->second->duration; return it->second->duration;
} }
@ -68,13 +66,11 @@ FileId VoiceNotesManager::on_get_voice_note(unique_ptr<VoiceNote> new_voice_note
const VoiceNotesManager::VoiceNote *VoiceNotesManager::get_voice_note(FileId file_id) const { const VoiceNotesManager::VoiceNote *VoiceNotesManager::get_voice_note(FileId file_id) const {
auto voice_note = voice_notes_.find(file_id); auto voice_note = voice_notes_.find(file_id);
if (voice_note == voice_notes_.end()) {
if (voice_note == voice_notes_.end() || return nullptr;
voice_note->second == nullptr ||
voice_note->second->file_id != file_id) {
return make_unique<VoiceNote>().get();
} }
CHECK(voice_note->second->file_id == file_id);
return voice_note->second.get(); return voice_note->second.get();
} }
@ -97,7 +93,7 @@ void VoiceNotesManager::merge_voice_notes(FileId new_id, FileId old_id, bool can
CHECK(old_ != nullptr); CHECK(old_ != nullptr);
auto new_it = voice_notes_.find(new_id); auto new_it = voice_notes_.find(new_id);
if (new_it == voice_notes_.end() || new_it->second == nullptr) { if (new_it == voice_notes_.end()) {
auto &old = voice_notes_[old_id]; auto &old = voice_notes_[old_id];
if (!can_delete_old) { if (!can_delete_old) {
dup_voice_note(new_id, old_id); dup_voice_note(new_id, old_id);

View File

@ -18,9 +18,7 @@ namespace td {
template <class StorerT> template <class StorerT>
void VoiceNotesManager::store_voice_note(FileId file_id, StorerT &storer) const { void VoiceNotesManager::store_voice_note(FileId file_id, StorerT &storer) const {
auto it = voice_notes_.find(file_id); auto it = voice_notes_.find(file_id);
if (it == voice_notes_.end() || it->second == nullptr) { CHECK(it != voice_notes_.end());
return;
}
const VoiceNote *voice_note = it->second.get(); const VoiceNote *voice_note = it->second.get();
store(voice_note->mime_type, storer); store(voice_note->mime_type, storer);
store(voice_note->duration, storer); store(voice_note->duration, storer);

View File

@ -408,17 +408,13 @@ WebPagesManager::WebPagesManager(Td *td, ActorShared<> parent) : td_(td), parent
void WebPagesManager::tear_down() { void WebPagesManager::tear_down() {
parent_.reset(); parent_.reset();
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup();
} }
WebPagesManager::~WebPagesManager() = default; WebPagesManager::~WebPagesManager() = default;
WebPageId WebPagesManager::on_get_web_page(tl_object_ptr<telegram_api::WebPage> &&web_page_ptr, WebPageId WebPagesManager::on_get_web_page(tl_object_ptr<telegram_api::WebPage> &&web_page_ptr,
DialogId owner_dialog_id) { DialogId owner_dialog_id) {
if (web_page_ptr == nullptr) { CHECK(web_page_ptr != nullptr);
return WebPageId();
}
LOG(DEBUG) << "Got " << to_string(web_page_ptr); LOG(DEBUG) << "Got " << to_string(web_page_ptr);
switch (web_page_ptr->get_id()) { switch (web_page_ptr->get_id()) {
case telegram_api::webPageEmpty::ID: { case telegram_api::webPageEmpty::ID: {
@ -546,15 +542,9 @@ WebPageId WebPagesManager::on_get_web_page(tl_object_ptr<telegram_api::WebPage>
void WebPagesManager::update_web_page(unique_ptr<WebPage> web_page, WebPageId web_page_id, bool from_binlog, void WebPagesManager::update_web_page(unique_ptr<WebPage> web_page, WebPageId web_page_id, bool from_binlog,
bool from_database) { bool from_database) {
LOG(INFO) << "Update " << web_page_id << (from_database ? " from database" : (from_binlog ? " from binlog" : "")); LOG(INFO) << "Update " << web_page_id << (from_database ? " from database" : (from_binlog ? " from binlog" : ""));
if (web_page == nullptr) { CHECK(web_page != nullptr);
return;
}
// Start custom-patches auto &page = web_pages_[web_page_id];
auto find_page = web_pages_.find(web_page_id);
if (find_page == web_pages_.end()) { return; }
auto &page = find_page->second;
// End custom-patches
auto old_file_ids = get_web_page_file_ids(page.get()); auto old_file_ids = get_web_page_file_ids(page.get());
WebPageInstantView old_instant_view; WebPageInstantView old_instant_view;
bool is_changed = true; bool is_changed = true;
@ -674,13 +664,8 @@ void WebPagesManager::on_get_web_page_instant_view_view_count(WebPageId web_page
return; return;
} }
// Start custom-patches auto *instant_view = &web_pages_[web_page_id]->instant_view;
auto find_web_page_val = web_pages_.find(web_page_id); CHECK(!instant_view->is_empty);
if (find_web_page_val == web_pages_.end()) { return; }
auto &web_page_val = find_web_page_val->second;
// End custom-patches
auto *instant_view = &web_page_val->instant_view;
if (instant_view->is_empty) { return; }
if (instant_view->view_count >= view_count) { if (instant_view->view_count >= view_count) {
return; return;
} }
@ -693,11 +678,7 @@ void WebPagesManager::on_get_web_page_instant_view_view_count(WebPageId web_page
} }
void WebPagesManager::on_get_web_page_by_url(const string &url, WebPageId web_page_id, bool from_database) { void WebPagesManager::on_get_web_page_by_url(const string &url, WebPageId web_page_id, bool from_database) {
// Start custom-patches auto &cached_web_page_id = url_to_web_page_id_[url];
auto find_cached_web_page_id = url_to_web_page_id_.find(url);
if (find_cached_web_page_id == url_to_web_page_id_.end()) { return; }
auto &cached_web_page_id = find_cached_web_page_id->second;
// End custom-patches
if (!from_database && G()->parameters().use_message_db) { if (!from_database && G()->parameters().use_message_db) {
if (web_page_id.is_valid()) { if (web_page_id.is_valid()) {
if (cached_web_page_id != web_page_id) { // not already saved if (cached_web_page_id != web_page_id) { // not already saved
@ -721,13 +702,8 @@ void WebPagesManager::register_web_page(WebPageId web_page_id, FullMessageId ful
} }
LOG(INFO) << "Register " << web_page_id << " from " << full_message_id << " from " << source; LOG(INFO) << "Register " << web_page_id << " from " << full_message_id << " from " << source;
// Start custom-patches bool is_inserted = web_page_messages_[web_page_id].insert(full_message_id).second;
auto find_web_page_message_ids = web_page_messages_.find(web_page_id); LOG_CHECK(is_inserted) << source << " " << web_page_id << " " << full_message_id;
if (find_web_page_message_ids == web_page_messages_.end()) { return; }
auto &web_page_message_ids = find_web_page_message_ids->second;
// End custom-patches
bool is_inserted = web_page_message_ids.insert(full_message_id).second;
if (!is_inserted) { return; }
if (!td_->auth_manager_->is_bot() && !have_web_page_force(web_page_id)) { if (!td_->auth_manager_->is_bot() && !have_web_page_force(web_page_id)) {
LOG(INFO) << "Waiting for " << web_page_id << " needed in " << full_message_id; LOG(INFO) << "Waiting for " << web_page_id << " needed in " << full_message_id;
@ -741,13 +717,8 @@ void WebPagesManager::unregister_web_page(WebPageId web_page_id, FullMessageId f
} }
LOG(INFO) << "Unregister " << web_page_id << " from " << full_message_id << " from " << source; LOG(INFO) << "Unregister " << web_page_id << " from " << full_message_id << " from " << source;
// Start custom-patches auto &message_ids = web_page_messages_[web_page_id];
auto find_message_ids = web_page_messages_.find(web_page_id);
if (find_message_ids == web_page_messages_.end()) { return; }
auto &message_ids = find_message_ids->second;
// End custom-patches
auto is_deleted = message_ids.erase(full_message_id) > 0; auto is_deleted = message_ids.erase(full_message_id) > 0;
if (!is_deleted) { return; }
LOG_CHECK(is_deleted) << source << " " << web_page_id << " " << full_message_id; LOG_CHECK(is_deleted) << source << " " << web_page_id << " " << full_message_id;
if (message_ids.empty()) { if (message_ids.empty()) {
@ -761,9 +732,7 @@ void WebPagesManager::unregister_web_page(WebPageId web_page_id, FullMessageId f
void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const string &url, void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const string &url,
tl_object_ptr<telegram_api::MessageMedia> &&message_media_ptr, tl_object_ptr<telegram_api::MessageMedia> &&message_media_ptr,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
if (message_media_ptr == nullptr) { CHECK(message_media_ptr != nullptr);
return;
}
int32 constructor_id = message_media_ptr->get_id(); int32 constructor_id = message_media_ptr->get_id();
if (constructor_id != telegram_api::messageMediaWebPage::ID) { if (constructor_id != telegram_api::messageMediaWebPage::ID) {
if (constructor_id == telegram_api::messageMediaEmpty::ID) { if (constructor_id == telegram_api::messageMediaEmpty::ID) {
@ -778,9 +747,7 @@ void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const st
} }
auto message_media_web_page = move_tl_object_as<telegram_api::messageMediaWebPage>(message_media_ptr); auto message_media_web_page = move_tl_object_as<telegram_api::messageMediaWebPage>(message_media_ptr);
if (message_media_web_page->webpage_ == nullptr) { CHECK(message_media_web_page->webpage_ != nullptr);
return;
}
auto web_page_id = on_get_web_page(std::move(message_media_web_page->webpage_), DialogId()); auto web_page_id = on_get_web_page(std::move(message_media_web_page->webpage_), DialogId());
if (web_page_id.is_valid() && !have_web_page(web_page_id)) { if (web_page_id.is_valid() && !have_web_page(web_page_id)) {
@ -794,9 +761,9 @@ void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const st
void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const string &url, WebPageId web_page_id, void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const string &url, WebPageId web_page_id,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
if (!(web_page_id == WebPageId() || have_web_page(web_page_id))) { return; } CHECK(web_page_id == WebPageId() || have_web_page(web_page_id));
if (!(got_web_page_previews_.find(request_id) == got_web_page_previews_.end())) { return; } CHECK(got_web_page_previews_.find(request_id) == got_web_page_previews_.end());
got_web_page_previews_[request_id] = web_page_id; got_web_page_previews_[request_id] = web_page_id;
if (web_page_id.is_valid() && !url.empty()) { if (web_page_id.is_valid() && !url.empty()) {
@ -809,7 +776,7 @@ void WebPagesManager::on_get_web_page_preview_success(int64 request_id, const st
void WebPagesManager::on_get_web_page_preview_fail(int64 request_id, const string &url, Status error, void WebPagesManager::on_get_web_page_preview_fail(int64 request_id, const string &url, Status error,
Promise<Unit> &&promise) { Promise<Unit> &&promise) {
LOG(INFO) << "Clean up getting of web page preview with url \"" << url << '"'; LOG(INFO) << "Clean up getting of web page preview with url \"" << url << '"';
if (!error.is_error()) { return; } CHECK(error.is_error());
promise.set_error(std::move(error)); promise.set_error(std::move(error));
} }
@ -859,9 +826,7 @@ tl_object_ptr<td_api::webPage> WebPagesManager::get_web_page_preview_result(int6
} }
auto it = got_web_page_previews_.find(request_id); auto it = got_web_page_previews_.find(request_id);
if (it == got_web_page_previews_.end()) { CHECK(it != got_web_page_previews_.end());
return nullptr;
}
auto web_page_id = it->second; auto web_page_id = it->second;
got_web_page_previews_.erase(it); got_web_page_previews_.erase(it);
return get_web_page_object(web_page_id); return get_web_page_object(web_page_id);
@ -922,9 +887,7 @@ void WebPagesManager::load_web_page_instant_view(WebPageId web_page_id, bool for
LOG(INFO) << "Load " << web_page_id << " instant view, have " << previous_queries << " previous queries"; LOG(INFO) << "Load " << web_page_id << " instant view, have " << previous_queries << " previous queries";
if (previous_queries == 0) { if (previous_queries == 0) {
const WebPageInstantView *web_page_instant_view = get_web_page_instant_view(web_page_id); const WebPageInstantView *web_page_instant_view = get_web_page_instant_view(web_page_id);
if (web_page_instant_view == nullptr) { CHECK(web_page_instant_view != nullptr);
return;
}
if (G()->parameters().use_message_db && !web_page_instant_view->was_loaded_from_database) { if (G()->parameters().use_message_db && !web_page_instant_view->was_loaded_from_database) {
LOG(INFO) << "Trying to load " << web_page_id << " instant view from database"; LOG(INFO) << "Trying to load " << web_page_id << " instant view from database";
@ -942,7 +905,7 @@ void WebPagesManager::load_web_page_instant_view(WebPageId web_page_id, bool for
void WebPagesManager::reload_web_page_instant_view(WebPageId web_page_id) { void WebPagesManager::reload_web_page_instant_view(WebPageId web_page_id) {
LOG(INFO) << "Reload " << web_page_id << " instant view"; LOG(INFO) << "Reload " << web_page_id << " instant view";
const WebPage *web_page = get_web_page(web_page_id); const WebPage *web_page = get_web_page(web_page_id);
if (!(web_page != nullptr && !web_page->instant_view.is_empty)) { return; } CHECK(web_page != nullptr && !web_page->instant_view.is_empty);
auto promise = PromiseCreator::lambda([web_page_id](Result<> result) { auto promise = PromiseCreator::lambda([web_page_id](Result<> result) {
send_closure(G()->web_pages_manager(), &WebPagesManager::update_web_page_instant_view_load_requests, web_page_id, send_closure(G()->web_pages_manager(), &WebPagesManager::update_web_page_instant_view_load_requests, web_page_id,
@ -961,7 +924,7 @@ void WebPagesManager::on_load_web_page_instant_view_from_database(WebPageId web_
if (G()->close_flag()) { if (G()->close_flag()) {
return; return;
} }
if (!(G()->parameters().use_message_db)) { return; } CHECK(G()->parameters().use_message_db);
LOG(INFO) << "Successfully loaded " << web_page_id << " instant view of size " << value.size() << " from database"; LOG(INFO) << "Successfully loaded " << web_page_id << " instant view of size " << value.size() << " from database";
// G()->td_db()->get_sqlite_pmc()->erase(get_web_page_instant_view_database_key(web_page_id), Auto()); // G()->td_db()->get_sqlite_pmc()->erase(get_web_page_instant_view_database_key(web_page_id), Auto());
// return; // return;
@ -1211,9 +1174,6 @@ tl_object_ptr<td_api::webPage> WebPagesManager::get_web_page_object(WebPageId we
if (web_page == nullptr) { if (web_page == nullptr) {
return nullptr; return nullptr;
} }
if (&web_page->url == nullptr) {
return nullptr;
}
int32 instant_view_version = [web_page] { int32 instant_view_version = [web_page] {
if (web_page->instant_view.is_empty) { if (web_page->instant_view.is_empty) {
return 0; return 0;
@ -1355,7 +1315,7 @@ void WebPagesManager::on_web_page_changed(WebPageId web_page_id, bool have_web_p
for (auto full_message_id : it->second) { for (auto full_message_id : it->second) {
full_message_ids.push_back(full_message_id); full_message_ids.push_back(full_message_id);
} }
if (full_message_ids.empty()) { return; } CHECK(!full_message_ids.empty());
for (auto full_message_id : full_message_ids) { for (auto full_message_id : full_message_ids) {
if (!have_web_page) { if (!have_web_page) {
td_->messages_manager_->delete_pending_message_web_page(full_message_id); td_->messages_manager_->delete_pending_message_web_page(full_message_id);
@ -1364,14 +1324,9 @@ void WebPagesManager::on_web_page_changed(WebPageId web_page_id, bool have_web_p
} }
} }
if (have_web_page) { if (have_web_page) {
// Start custom-patches CHECK(web_page_messages_[web_page_id].size() == full_message_ids.size());
auto find_web_page_message_ids = web_page_messages_.find(web_page_id);
if (find_web_page_message_ids == web_page_messages_.end()) { return; }
auto &web_page_message_ids = find_web_page_message_ids->second;
// End custom-patches
if (!(web_page_message_ids.size() == full_message_ids.size())) { return; }
} else { } else {
if (!(web_page_messages_.count(web_page_id) == 0)) { return; } CHECK(web_page_messages_.count(web_page_id) == 0);
} }
} }
auto get_it = pending_get_web_pages_.find(web_page_id); auto get_it = pending_get_web_pages_.find(web_page_id);
@ -1388,14 +1343,12 @@ void WebPagesManager::on_web_page_changed(WebPageId web_page_id, bool have_web_p
const WebPagesManager::WebPage *WebPagesManager::get_web_page(WebPageId web_page_id) const { const WebPagesManager::WebPage *WebPagesManager::get_web_page(WebPageId web_page_id) const {
auto p = web_pages_.find(web_page_id); auto p = web_pages_.find(web_page_id);
if (p == web_pages_.end()) {
if (p == web_pages_.end() ||
p->second == nullptr) {
return nullptr; return nullptr;
} } else {
return p->second.get(); return p->second.get();
} }
}
const WebPagesManager::WebPageInstantView *WebPagesManager::get_web_page_instant_view(WebPageId web_page_id) const { const WebPagesManager::WebPageInstantView *WebPagesManager::get_web_page_instant_view(WebPageId web_page_id) const {
const WebPage *web_page = get_web_page(web_page_id); const WebPage *web_page = get_web_page(web_page_id);
@ -1446,9 +1399,7 @@ void WebPagesManager::on_pending_web_page_timeout(WebPageId web_page_id) {
void WebPagesManager::on_get_web_page_instant_view(WebPage *web_page, tl_object_ptr<telegram_api::page> &&page, void WebPagesManager::on_get_web_page_instant_view(WebPage *web_page, tl_object_ptr<telegram_api::page> &&page,
int32 hash, DialogId owner_dialog_id) { int32 hash, DialogId owner_dialog_id) {
if (page == nullptr) { CHECK(page != nullptr);
return;
}
std::unordered_map<int64, Photo> photos; std::unordered_map<int64, Photo> photos;
for (auto &photo_ptr : page->photos_) { for (auto &photo_ptr : page->photos_) {
Photo photo = get_photo(td_->file_manager_.get(), std::move(photo_ptr), owner_dialog_id); Photo photo = get_photo(td_->file_manager_.get(), std::move(photo_ptr), owner_dialog_id);
@ -1563,9 +1514,7 @@ void WebPagesManager::save_web_page(const WebPage *web_page, WebPageId web_page_
return; return;
} }
if (web_page == nullptr) { CHECK(web_page != nullptr);
return;
}
if (!from_binlog) { if (!from_binlog) {
WebPageLogEvent log_event(web_page_id, web_page); WebPageLogEvent log_event(web_page_id, web_page);
auto storer = get_log_event_storer(log_event); auto storer = get_log_event_storer(log_event);
@ -1601,9 +1550,7 @@ void WebPagesManager::on_binlog_web_page_event(BinlogEvent &&event) {
auto web_page_id = log_event.web_page_id; auto web_page_id = log_event.web_page_id;
LOG(INFO) << "Add " << web_page_id << " from binlog"; LOG(INFO) << "Add " << web_page_id << " from binlog";
auto web_page = std::move(log_event.web_page_out); auto web_page = std::move(log_event.web_page_out);
if (web_page == nullptr) { CHECK(web_page != nullptr);
return;
}
web_page->log_event_id = event.id_; web_page->log_event_id = event.id_;
@ -1667,7 +1614,7 @@ void WebPagesManager::on_load_web_page_from_database(WebPageId web_page_id, stri
vector<Promise<Unit>> promises; vector<Promise<Unit>> promises;
if (it != load_web_page_from_database_queries_.end()) { if (it != load_web_page_from_database_queries_.end()) {
promises = std::move(it->second); promises = std::move(it->second);
if (promises.empty()) { return; } CHECK(!promises.empty());
load_web_page_from_database_queries_.erase(it); load_web_page_from_database_queries_.erase(it);
} }
@ -1730,16 +1677,8 @@ FileSourceId WebPagesManager::get_url_file_source_id(const string &url) {
const WebPage *web_page = get_web_page(web_page_id); const WebPage *web_page = get_web_page(web_page_id);
if (web_page != nullptr) { if (web_page != nullptr) {
if (!web_page->file_source_id.is_valid()) { if (!web_page->file_source_id.is_valid()) {
// Start custom-patches web_pages_[web_page_id]->file_source_id =
auto find_web_page_val = web_pages_.find(web_page_id);
if (find_web_page_val != web_pages_.end()) {
auto &web_page_val = find_web_page_val->second;
// End custom-patches
web_page_val->file_source_id =
td_->file_reference_manager_->create_web_page_file_source(web_page->url); td_->file_reference_manager_->create_web_page_file_source(web_page->url);
// Start custom-patches
}
// End custom-patches
} }
return web_page->file_source_id; return web_page->file_source_id;
} }
@ -1793,20 +1732,6 @@ vector<FileId> WebPagesManager::get_web_page_file_ids(const WebPage *web_page) c
return result; return result;
} }
void WebPagesManager::memory_cleanup() {
web_pages_.clear();
web_pages_.rehash(0);
loaded_from_database_web_pages_.clear();
loaded_from_database_web_pages_.rehash(0);
web_page_messages_.clear();
web_page_messages_.rehash(0);
got_web_page_previews_.clear();
got_web_page_previews_.rehash(0);
url_to_web_page_id_.clear();
url_to_web_page_id_.rehash(0);
url_to_file_source_id_.clear();
url_to_file_source_id_.rehash(0);
}
void WebPagesManager::memory_stats(vector<string> &output) { void WebPagesManager::memory_stats(vector<string> &output) {
output.push_back("\"web_pages_\":"); output.push_back(std::to_string(web_pages_.size())); output.push_back("\"web_pages_\":"); output.push_back(std::to_string(web_pages_.size()));
output.push_back(","); output.push_back(",");
@ -1821,4 +1746,5 @@ void WebPagesManager::memory_stats(vector<string> &output) {
output.push_back("\"url_to_file_source_id_\":"); output.push_back(std::to_string(url_to_file_source_id_.size())); output.push_back("\"url_to_file_source_id_\":"); output.push_back(std::to_string(url_to_file_source_id_.size()));
} }
} // namespace td } // namespace td

View File

@ -37,8 +37,6 @@ class WebPagesManager final : public Actor {
public: public:
WebPagesManager(Td *td, ActorShared<> parent); WebPagesManager(Td *td, ActorShared<> parent);
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
WebPagesManager(const WebPagesManager &) = delete; WebPagesManager(const WebPagesManager &) = delete;

View File

@ -9,7 +9,6 @@
#include "td/utils/common.h" #include "td/utils/common.h"
#include "td/utils/StringBuilder.h" #include "td/utils/StringBuilder.h"
#include <ctime>
#include <functional> #include <functional>
#include <type_traits> #include <type_traits>
@ -18,15 +17,11 @@ namespace td {
class FileId { class FileId {
int32 id = 0; int32 id = 0;
int32 remote_id = 0; int32 remote_id = 0;
int64 time_ = INT64_MAX;
public: public:
FileId() { FileId() = default;
set_time();
}
FileId(int32 file_id, int32 remote_id) : id(file_id), remote_id(remote_id) { FileId(int32 file_id, int32 remote_id) : id(file_id), remote_id(remote_id) {
set_time();
} }
template <class T1, class T2, typename = std::enable_if_t<std::is_convertible<T1, int32>::value>, template <class T1, class T2, typename = std::enable_if_t<std::is_convertible<T1, int32>::value>,
typename = std::enable_if_t<std::is_convertible<T2, int32>::value>> typename = std::enable_if_t<std::is_convertible<T2, int32>::value>>
@ -43,18 +38,6 @@ class FileId {
return id; return id;
} }
void set_time() {
time_ = std::time(nullptr);
}
int64 get_time() const {
return time_;
}
void reset_time() {
time_ = INT64_MAX;
}
int32 get_remote() const { int32 get_remote() const {
return remote_id; return remote_id;
} }

View File

@ -136,9 +136,7 @@ FileNode &FileNodePtr::operator*() const {
FileNode *FileNodePtr::get() const { FileNode *FileNodePtr::get() const {
auto res = get_unsafe(); auto res = get_unsafe();
if (res == nullptr) { CHECK(res);
return {};
}
return res; return res;
} }
@ -147,9 +145,7 @@ FullRemoteFileLocation *FileNodePtr::get_remote() const {
} }
FileNode *FileNodePtr::get_unsafe() const { FileNode *FileNodePtr::get_unsafe() const {
if (file_manager_ == nullptr) { CHECK(file_manager_ != nullptr);
return {};
}
return file_manager_->get_file_node_raw(file_id_); return file_manager_->get_file_node_raw(file_id_);
} }
@ -802,17 +798,11 @@ void prepare_path_for_pmc(FileType file_type, string &path) {
FileManager::FileManager(unique_ptr<Context> context) : context_(std::move(context)) { FileManager::FileManager(unique_ptr<Context> context) : context_(std::move(context)) {
if (G()->parameters().use_file_db) { if (G()->parameters().use_file_db) {
file_db_ = G()->td_db()->get_file_db_shared(); file_db_ = G()->td_db()->get_file_db_shared();
use_standard_algorithm_ = true;
} else {
use_standard_algorithm_ = false;
} }
parent_ = context_->create_reference(); parent_ = context_->create_reference();
// only the original tdlib algorithm requires a next_file_id() call at startup
if (use_standard_algorithm_) {
next_file_id(); next_file_id();
next_file_node_id(); next_file_node_id();
}
std::unordered_set<string> dir_paths; std::unordered_set<string> dir_paths;
for (int32 i = 0; i < MAX_FILE_TYPE; i++) { for (int32 i = 0; i < MAX_FILE_TYPE; i++) {
@ -1053,8 +1043,8 @@ bool FileManager::try_fix_partial_local_location(FileNodePtr node) {
} }
FileManager::FileIdInfo *FileManager::get_file_id_info(FileId file_id) { FileManager::FileIdInfo *FileManager::get_file_id_info(FileId file_id) {
file_id.set_time(); // update last access time of FileId CHECK(static_cast<size_t>(file_id.get()) < file_id_info_.size());
return &file_id_info_.at(file_id.get()); return &file_id_info_[file_id.get()];
} }
FileId FileManager::dup_file_id(FileId file_id) { FileId FileManager::dup_file_id(FileId file_id) {
@ -1089,16 +1079,7 @@ void FileManager::try_forget_file_id(FileId file_id) {
bool is_removed = td::remove(file_node->file_ids_, file_id); bool is_removed = td::remove(file_node->file_ids_, file_id);
CHECK(is_removed); CHECK(is_removed);
*info = FileIdInfo(); *info = FileIdInfo();
if (use_standard_algorithm_) { empty_file_ids_.push_back(file_id.get());
file_id_info_.erase(file_id.get());
} else {
file_id_info_.erase(file_id.get());
// Start custom-patches
file_id.reset_time(); // delete last access time of FileId
destroy_query(file_id.get());
context_->destroy_file_source(file_id);
// End custom-patches
}
} }
FileId FileManager::register_empty(FileType type) { FileId FileManager::register_empty(FileType type) {
@ -1113,13 +1094,7 @@ void FileManager::on_file_unlink(const FullLocalFileLocation &location) {
} }
auto file_id = it->second; auto file_id = it->second;
auto file_node = get_sync_file_node(file_id); auto file_node = get_sync_file_node(file_id);
if (use_standard_algorithm_) {
CHECK(file_node); CHECK(file_node);
} else {
if (!file_node) {
return;
}
}
file_node->drop_local_location(); file_node->drop_local_location();
try_flush_node_info(file_node, "on_file_unlink"); try_flush_node_info(file_node, "on_file_unlink");
} }
@ -1249,8 +1224,8 @@ Result<FileId> FileManager::register_file(FileData &&data, FileLocationSource fi
int32 remote_key = 0; int32 remote_key = 0;
if (file_view.has_remote_location()) { if (file_view.has_remote_location()) {
RemoteInfo info{file_view.remote_location(), file_location_source, file_id}; RemoteInfo info{file_view.remote_location(), file_location_source, file_id};
RemoteInfo stored_info; remote_key = remote_location_info_.add(info);
std::tie(remote_key, stored_info) = remote_location_info_.add_and_get(info); auto &stored_info = remote_location_info_.get(remote_key);
if (stored_info.file_id_ == file_id) { if (stored_info.file_id_ == file_id) {
get_file_id_info(file_id)->pin_flag_ = true; get_file_id_info(file_id)->pin_flag_ = true;
new_remote = true; new_remote = true;
@ -1706,7 +1681,7 @@ Result<FileId> FileManager::merge(FileId x_file_id, FileId y_file_id, bool no_sy
} }
} }
file_nodes_.erase(node_ids[other_node_i]); file_nodes_[node_ids[other_node_i]] = nullptr;
run_generate(node); run_generate(node);
run_download(node, false); run_download(node, false);
@ -1914,25 +1889,17 @@ void FileManager::flush_to_pmc(FileNodePtr node, bool new_remote, bool new_local
} }
FileNode *FileManager::get_file_node_raw(FileId file_id, FileNodeId *file_node_id) { FileNode *FileManager::get_file_node_raw(FileId file_id, FileNodeId *file_node_id) {
if (file_id.get() <= 0) { if (file_id.get() <= 0 || file_id.get() >= static_cast<int32>(file_id_info_.size())) {
return nullptr; return nullptr;
} }
auto find_file_id_info = file_id_info_.find(file_id.get()); FileNodeId node_id = file_id_info_[file_id.get()].node_id_;
if (find_file_id_info == file_id_info_.end()) {
return nullptr;
}
FileNodeId node_id = find_file_id_info->second.node_id_;
if (node_id == 0) { if (node_id == 0) {
return nullptr; return nullptr;
} }
auto find_file_nodes = file_nodes_.find(node_id);
if (find_file_nodes == file_nodes_.end()) {
return nullptr;
}
if (file_node_id != nullptr) { if (file_node_id != nullptr) {
*file_node_id = node_id; *file_node_id = node_id;
} }
return find_file_nodes->second.get(); return file_nodes_[node_id].get();
} }
FileNodePtr FileManager::get_sync_file_node(FileId file_id) { FileNodePtr FileManager::get_sync_file_node(FileId file_id) {
@ -3093,9 +3060,8 @@ Result<FileId> FileManager::check_input_file_id(FileType type, Result<FileId> re
int32 remote_id = file_id.get_remote(); int32 remote_id = file_id.get_remote();
if (remote_id == 0) { if (remote_id == 0) {
RemoteInfo info{file_view.remote_location(), FileLocationSource::FromUser, file_id}; RemoteInfo info{file_view.remote_location(), FileLocationSource::FromUser, file_id};
RemoteInfo stored_info; remote_id = remote_location_info_.add(info);
std::tie(remote_id, stored_info) = remote_location_info_.add_and_get(info); if (remote_location_info_.get(remote_id).file_id_ == file_id) {
if (stored_info.file_id_ == file_id) {
get_file_id_info(file_id)->pin_flag_ = true; get_file_id_info(file_id)->pin_flag_ = true;
} }
} }
@ -3377,17 +3343,20 @@ string FileManager::extract_file_reference(const tl_object_ptr<telegram_api::Inp
} }
FileId FileManager::next_file_id() { FileId FileManager::next_file_id() {
auto id = file_id_seqno++; if (!empty_file_ids_.empty()) {
FileId res(static_cast<int32>(id), 0); auto res = empty_file_ids_.back();
file_id_info_[id] = {}; empty_file_ids_.pop_back();
res.set_time(); // update last access time of FileId return FileId{res, 0};
}
FileId res(static_cast<int32>(file_id_info_.size()), 0);
// LOG(ERROR) << "NEXT file_id " << res;
file_id_info_.push_back({});
return res; return res;
} }
FileManager::FileNodeId FileManager::next_file_node_id() { FileManager::FileNodeId FileManager::next_file_node_id() {
auto id = file_node_seqno++; FileNodeId res = static_cast<FileNodeId>(file_nodes_.size());
auto res = static_cast<FileNodeId>(id); file_nodes_.emplace_back(nullptr);
file_nodes_[id] = nullptr;
return res; return res;
} }
@ -3397,9 +3366,7 @@ void FileManager::on_start_download(QueryId query_id) {
} }
auto query = queries_container_.get(query_id); auto query = queries_container_.get(query_id);
if (query == nullptr) { CHECK(query != nullptr);
return;
}
auto file_id = query->file_id_; auto file_id = query->file_id_;
auto file_node = get_file_node(file_id); auto file_node = get_file_node(file_id);
@ -3422,9 +3389,7 @@ void FileManager::on_partial_download(QueryId query_id, const PartialLocalFileLo
} }
auto query = queries_container_.get(query_id); auto query = queries_container_.get(query_id);
if (query == nullptr) { CHECK(query != nullptr);
return;
}
auto file_id = query->file_id_; auto file_id = query->file_id_;
auto file_node = get_file_node(file_id); auto file_node = get_file_node(file_id);
@ -3453,9 +3418,7 @@ void FileManager::on_hash(QueryId query_id, string hash) {
} }
auto query = queries_container_.get(query_id); auto query = queries_container_.get(query_id);
if (query == nullptr) { CHECK(query != nullptr);
return;
}
auto file_id = query->file_id_; auto file_id = query->file_id_;
@ -3478,9 +3441,7 @@ void FileManager::on_partial_upload(QueryId query_id, const PartialRemoteFileLoc
} }
auto query = queries_container_.get(query_id); auto query = queries_container_.get(query_id);
if (query == nullptr) { CHECK(query != nullptr);
return;
}
auto file_id = query->file_id_; auto file_id = query->file_id_;
auto file_node = get_file_node(file_id); auto file_node = get_file_node(file_id);
@ -3621,9 +3582,7 @@ void FileManager::on_partial_generate(QueryId query_id, const PartialLocalFileLo
} }
auto query = queries_container_.get(query_id); auto query = queries_container_.get(query_id);
if (query == nullptr) { CHECK(query != nullptr);
return;
}
auto file_id = query->file_id_; auto file_id = query->file_id_;
auto file_node = get_file_node(file_id); auto file_node = get_file_node(file_id);
@ -3920,334 +3879,6 @@ void FileManager::hangup() {
stop(); stop();
} }
void FileManager::destroy_query(int32 file_id) {
if (use_standard_algorithm_) {
return;
}
for (auto &query_id : queries_container_.ids()) {
auto query = queries_container_.get(query_id);
if (query != nullptr && file_id == query->file_id_.get()) {
on_error(query_id, Status::Error(400, "FILE_DOWNLOAD_RESTART"));
}
}
}
void FileManager::memory_cleanup() {
memory_cleanup(false);
}
void FileManager::memory_cleanup(bool full) {
if (use_standard_algorithm_) {
return;
}
if (!full) {
LOG(INFO) << "Initial registered ids: " << file_id_info_.size() << " registered nodes: " << file_nodes_.size();
}
std::unordered_set<int32> file_to_be_deleted = {};
auto file_ttl = full ? 0 : !G()->shared_config().get_option_integer("delete_file_reference_after_seconds", 30);
/* DESTROY OLD file_id_info_ */
if (full) {
file_id_info_.clear();
} else {
auto it = file_id_info_.begin();
auto time = std::time(nullptr);
while (it != file_id_info_.end()) {
auto find_node = file_nodes_.find(it->second.node_id_);
if (find_node != file_nodes_.end()) {
auto &node = find_node->second;
if (time - node->main_file_id_.get_time() > file_ttl) {
auto can_reset = node->download_priority_ == 0;
can_reset &= node->generate_download_priority_ == 0;
can_reset &= node->download_id_ == 0;
if (can_reset) {
auto file_ids_it = node->file_ids_.begin();
while (file_ids_it != node->file_ids_.end() && can_reset) {
auto find_file = file_id_info_.find(file_ids_it->get());
if (find_file != file_id_info_.end()) {
auto &file = find_file->second;
can_reset &= file.download_priority_ == 0;
can_reset &= time - file_ids_it->get_time() > file_ttl;
}
file_ids_it++;
}
}
if (can_reset) {
node->main_file_id_.reset_time(); // delete last access time of FileId
for (auto &file_id : node->file_ids_) {
file_id.reset_time(); // delete last access time of FileId
/* DESTROY ASSOCIATED QUERIES */
destroy_query(file_id.get());
/* DESTROY ASSOCIATED LATE */
file_to_be_deleted.insert(file_id.get());
}
/* DESTROY MAIN QUERY */
destroy_query(it->first);
/* DESTROY MAIN NODE */
file_nodes_.erase(it->second.node_id_);
/* DESTROY MAIN FILE LATE */
file_to_be_deleted.insert(it->first);
}
}
} else {
/* The file has a nonexistent node associated */
file_to_be_deleted.insert(it->first);
}
it++;
}
for (auto file_id : file_to_be_deleted) {
context_->destroy_file_source({file_id, 0});
file_id_info_.erase(file_id);
}
}
/* DESTROY INVALID FILES */
if (!full) {
auto it = file_id_info_.begin();
while (it != file_id_info_.end()) {
auto is_invalid = false;
if (it->second.node_id_ != 0) {
auto find_file_node = file_nodes_.find(it->second.node_id_);
if (find_file_node == file_nodes_.end() || find_file_node->second->empty) {
is_invalid = true;
destroy_query(it->first);
context_->destroy_file_source({it->first, 0});
file_nodes_.erase(it->second.node_id_);
}
} else {
is_invalid = true;
}
if (is_invalid) {
it = file_id_info_.erase(it);
} else {
it++;
}
}
}
/* DESTROY INVALID file_nodes_ */
if (full) {
file_nodes_.clear();
} else {
auto it = file_nodes_.begin();
while (it != file_nodes_.end()) {
auto is_invalid = false;
if (it->second == nullptr || it->second->empty) {
is_invalid = true;
} else {
if (it->second->main_file_id_.empty()) {
is_invalid = true;
} else {
auto find_file_id_info = file_id_info_.find(it->second->main_file_id_.get());
if (find_file_id_info != file_id_info_.end()) {
if (find_file_id_info->second.node_id_ == 0) {
for (auto &file_id : it->second->file_ids_) {
context_->destroy_file_source(file_id);
file_id_info_.erase(file_id.get());
}
file_id_info_.erase(it->second->main_file_id_.get());
is_invalid = true;
}
} else {
// todo: is it invalid or not here?
is_invalid = true;
}
}
}
if (is_invalid) {
it = file_nodes_.erase(it);
} else {
it++;
}
}
}
/* DESTROY INVALID file_hash_to_file_id_ */
if (full) {
file_hash_to_file_id_.clear();
} else {
auto it = file_hash_to_file_id_.begin();
while (it != file_hash_to_file_id_.end()) {
auto is_invalid = false;
auto find_file = file_id_info_.find(it->second.get());
if (find_file != file_id_info_.end()) {
auto &file = find_file->second;
auto find_file_node = file_nodes_.find(file.node_id_);
if (find_file_node == file_nodes_.end() || find_file_node->second->empty) {
is_invalid = true;
file_nodes_.erase(file.node_id_);
}
} else {
is_invalid = true;
}
if (is_invalid) {
it = file_hash_to_file_id_.erase(it);
} else {
it++;
}
}
}
/* DESTROY INVALID local_location_to_file_id_ */
if (full) {
local_location_to_file_id_.clear();
} else {
auto it = local_location_to_file_id_.begin();
while (it != local_location_to_file_id_.end()) {
auto is_invalid = false;
auto find_file = file_id_info_.find(it->second.get());
if (find_file != file_id_info_.end()) {
auto &file = find_file->second;
auto find_file_node = file_nodes_.find(file.node_id_);
if (find_file_node == file_nodes_.end() || find_file_node->second->empty) {
is_invalid = true;
file_nodes_.erase(file.node_id_);
}
} else {
is_invalid = true;
}
if (is_invalid) {
it = local_location_to_file_id_.erase(it);
} else {
it++;
}
}
}
/* DESTROY INVALID generate_location_to_file_id_ */
if (full) {
generate_location_to_file_id_.clear();
} else {
auto it = generate_location_to_file_id_.begin();
while (it != generate_location_to_file_id_.end()) {
auto is_invalid = false;
auto find_file = file_id_info_.find(it->second.get());
if (find_file != file_id_info_.end()) {
auto &file = find_file->second;
auto find_file_node = file_nodes_.find(file.node_id_);
if (find_file_node == file_nodes_.end() || find_file_node->second->empty) {
is_invalid = true;
file_nodes_.erase(file.node_id_);
}
} else {
is_invalid = true;
}
if (is_invalid) {
it = generate_location_to_file_id_.erase(it);
} else {
it++;
}
}
}
/* DESTROY INVALID remote_location_info_ */
if (full) {
remote_location_info_.clear();
} else {
remote_location_info_.lock_access_mutex();
std::unordered_map<int32, RemoteInfo> old_remote_info = {};
{
auto map = remote_location_info_.get_map();
auto it = map.begin();
while (it != map.end()) {
old_remote_info[it->second] = it->first;
it++;
}
}
auto it = old_remote_info.begin();
while (it != old_remote_info.end()) {
auto is_invalid = false;
auto find_file = file_id_info_.find(it->second.file_id_.get());
if (find_file != file_id_info_.end()) {
auto &file = find_file->second;
auto find_file_node = file_nodes_.find(file.node_id_);
if (find_file_node == file_nodes_.end() || find_file_node->second->empty) {
is_invalid = true;
file_nodes_.erase(file.node_id_);
}
} else {
is_invalid = true;
}
if (is_invalid) {
remote_location_info_.erase_unsafe(it->first);
}
it++;
}
remote_location_info_.unlock_access_mutex();
}
/* DESTROY NULL file_id_info_ */
if (full) {
file_id_info_.clear();
} else {
auto it = file_id_info_.begin();
while (it != file_id_info_.end()) {
auto is_invalid = false;
if (it->second.node_id_ != 0) {
auto find_file_node = file_nodes_.find(it->second.node_id_);
if (find_file_node == file_nodes_.end() || find_file_node->second->empty) {
is_invalid = true;
context_->destroy_file_source({it->first, 0});
}
} else {
is_invalid = true;
}
if (is_invalid) {
it = file_id_info_.erase(it);
} else {
it++;
}
}
}
if (full) {
file_nodes_.rehash(0);
file_hash_to_file_id_.rehash(0);
file_id_info_.rehash(0);
} else {
file_nodes_.rehash(file_nodes_.size() + 1);
file_hash_to_file_id_.rehash(file_hash_to_file_id_.size() + 1);
file_id_info_.rehash(file_id_info_.size() + 1);
}
if (!full) {
LOG(INFO) << "Final registered ids: " << file_id_info_.size() << " registered nodes: " << file_nodes_.size();
}
}
void FileManager::memory_stats(vector<string> &output) { void FileManager::memory_stats(vector<string> &output) {
output.push_back("\"file_id_info_\":"); output.push_back(std::to_string(file_id_info_.size())); output.push_back("\"file_id_info_\":"); output.push_back(std::to_string(file_id_info_.size()));
output.push_back(","); output.push_back(",");
@ -4255,17 +3886,13 @@ void FileManager::memory_stats(vector<string> &output) {
output.push_back(","); output.push_back(",");
output.push_back("\"file_hash_to_file_id_\":"); output.push_back(std::to_string(file_hash_to_file_id_.size())); output.push_back("\"file_hash_to_file_id_\":"); output.push_back(std::to_string(file_hash_to_file_id_.size()));
output.push_back(","); output.push_back(",");
output.push_back("\"file_id_seqno\":"); output.push_back(std::to_string(file_id_seqno)); output.push_back("\"empty_file_ids_\":"); output.push_back(std::to_string(empty_file_ids_.size()));
output.push_back(","); output.push_back(",");
output.push_back("\"file_node_seqno\":"); output.push_back(std::to_string(file_node_seqno)); output.push_back("\"pmc_id_to_file_node_id_\":"); output.push_back(std::to_string(pmc_id_to_file_node_id_.size()));
} }
void FileManager::tear_down() { void FileManager::tear_down() {
parent_.reset(); parent_.reset();
if (G()->memory_manager().get_actor_unsafe()->can_manage_memory()) {
// Completely clear memory when closing, to avoid memory leaks
memory_cleanup(true);
}
} }
} // namespace td } // namespace td

View File

@ -68,12 +68,10 @@ struct NewRemoteFileLocation {
class FileNode { class FileNode {
public: public:
FileNode() {empty = true;}
FileNode(LocalFileLocation local, NewRemoteFileLocation remote, unique_ptr<FullGenerateFileLocation> generate, FileNode(LocalFileLocation local, NewRemoteFileLocation remote, unique_ptr<FullGenerateFileLocation> generate,
int64 size, int64 expected_size, string remote_name, string url, DialogId owner_dialog_id, int64 size, int64 expected_size, string remote_name, string url, DialogId owner_dialog_id,
FileEncryptionKey key, FileId main_file_id, int8 main_file_id_priority) FileEncryptionKey key, FileId main_file_id, int8 main_file_id_priority)
: empty(false) : local_(std::move(local))
, local_(std::move(local))
, remote_(std::move(remote)) , remote_(std::move(remote))
, generate_(std::move(generate)) , generate_(std::move(generate))
, size_(size) , size_(size)
@ -121,7 +119,6 @@ class FileNode {
void on_info_flushed(); void on_info_flushed();
string suggested_path() const; string suggested_path() const;
bool empty = false;
private: private:
friend class FileView; friend class FileView;
@ -154,7 +151,7 @@ class FileNode {
FileDbId pmc_id_; FileDbId pmc_id_;
std::vector<FileId> file_ids_; std::vector<FileId> file_ids_;
FileId main_file_id_ = {}; FileId main_file_id_;
double last_successful_force_reupload_time_ = -1e10; double last_successful_force_reupload_time_ = -1e10;
@ -199,8 +196,6 @@ class FileManager;
class FileNodePtr { class FileNodePtr {
public: public:
FileNodePtr() = default; FileNodePtr() = default;
FileNodePtr(FileManager *file_manager) : file_manager_(file_manager) {
}
FileNodePtr(FileId file_id, FileManager *file_manager) : file_id_(file_id), file_manager_(file_manager) { FileNodePtr(FileId file_id, FileManager *file_manager) : file_id_(file_id), file_manager_(file_manager) {
} }
@ -348,8 +343,6 @@ class FileView {
class FileManager final : public FileLoadManager::Callback { class FileManager final : public FileLoadManager::Callback {
public: public:
void memory_cleanup();
void memory_stats(vector<string> &output); void memory_stats(vector<string> &output);
class DownloadCallback { class DownloadCallback {
@ -390,8 +383,6 @@ class FileManager final : public FileLoadManager::Callback {
virtual void on_file_updated(FileId size) = 0; virtual void on_file_updated(FileId size) = 0;
virtual void destroy_file_source(FileId file_id) = 0;
virtual bool add_file_source(FileId file_id, FileSourceId file_source_id) = 0; virtual bool add_file_source(FileId file_id, FileSourceId file_source_id) = 0;
virtual bool remove_file_source(FileId file_id, FileSourceId file_source_id) = 0; virtual bool remove_file_source(FileId file_id, FileSourceId file_source_id) = 0;
@ -511,10 +502,6 @@ class FileManager final : public FileLoadManager::Callback {
FileId parse_file(ParserT &parser); FileId parse_file(ParserT &parser);
private: private:
void destroy_query(int32 file_id);
void memory_cleanup(bool full);
Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted, bool allow_zero, Result<FileId> check_input_file_id(FileType type, Result<FileId> result, bool is_encrypted, bool allow_zero,
bool is_secure) TD_WARN_UNUSED_RESULT; bool is_secure) TD_WARN_UNUSED_RESULT;
@ -565,7 +552,6 @@ class FileManager final : public FileLoadManager::Callback {
ActorShared<> parent_; ActorShared<> parent_;
unique_ptr<Context> context_; unique_ptr<Context> context_;
std::shared_ptr<FileDbInterface> file_db_; std::shared_ptr<FileDbInterface> file_db_;
bool use_standard_algorithm_;
FileIdInfo *get_file_id_info(FileId file_id); FileIdInfo *get_file_id_info(FileId file_id);
@ -583,17 +569,15 @@ class FileManager final : public FileLoadManager::Callback {
}; };
Enumerator<RemoteInfo> remote_location_info_; Enumerator<RemoteInfo> remote_location_info_;
FileNodeId file_node_seqno = 1;
int32 file_id_seqno = 1;
std::unordered_map<string, FileId> file_hash_to_file_id_; std::unordered_map<string, FileId> file_hash_to_file_id_;
std::map<FullLocalFileLocation, FileId> local_location_to_file_id_; std::map<FullLocalFileLocation, FileId> local_location_to_file_id_;
std::map<FullGenerateFileLocation, FileId> generate_location_to_file_id_; std::map<FullGenerateFileLocation, FileId> generate_location_to_file_id_;
std::map<FileDbId, int32> pmc_id_to_file_node_id_; std::map<FileDbId, int32> pmc_id_to_file_node_id_;
std::unordered_map<int32, FileIdInfo> file_id_info_; vector<FileIdInfo> file_id_info_;
std::unordered_map<FileNodeId, unique_ptr<FileNode>> file_nodes_; vector<int32> empty_file_ids_;
vector<unique_ptr<FileNode>> file_nodes_;
ActorOwn<FileLoadManager> file_load_manager_; ActorOwn<FileLoadManager> file_load_manager_;
ActorOwn<FileGenerateManager> file_generate_manager_; ActorOwn<FileGenerateManager> file_generate_manager_;