Tuesday, 30 August 2022

MariaDB/MySQL - Fix error "Unknown/unsupported storage engine: InnoDB" by using recover mode

Although the InnoDB storage engine has mechanisms to preserve data, problems such as power failure or sudden restart can still cause errors in MySQL/MariaDB data. These errors can make the system unable to boot, unable to restore the normal data state. Some of the error messages we often encounter are listed below.


[Note] InnoDB: Starting shutdown...
[ERROR] InnoDB: Database was not shut down normally!
[ERROR] Plugin 'InnoDB' init function returned error.
[ERROR] Plugin 'InnoDB' registration as a STORAGE ENGINE failed.
[Note] Plugin 'FEEDBACK' is disabled.
[ERROR] InnoDB: Starting crash recovery from checkpoint LSN=1637690
[ERROR] Unknown/unsupported storage engine: InnoDB
[ERROR] Aborting



Note: Some crashes are caused by other causes but also return the error message "Unknown/unsupported storage engine: InnoDB". In that case, there will be more detailed information in the MySQL log to help you find the cause and handle it. As for the cases where the service can't tell why InnoDB is unsupported or unrecoverable, most of the time, data errors are caused. You can handle that case according to the instructions in this article.

To use this mode is very simple. You just need to specify the value innodb_force_recovery in the installation file of MySQL or MariaDB. Then restart the service. MySQL will restart and try to use recovery mode to recover the corrupted data.


[mysqld]
innodb_force_recovery = 1

MySQL has a total of 6 recovery modes in ascending severity. You often choose to get the most suitable mode for your system. Please try again with a higher level if the error is not resolved.


1 (SRV_FORCE_IGNORE_CORRUPT)
Lets the server run even if it detects a corrupt page. Tries to make SELECT * FROM tbl_name jump over corrupt index records and pages, which helps in dumping tables.

2 (SRV_FORCE_NO_BACKGROUND)
Prevents the master thread and any purge threads from running. If an unexpected exit would occur during the purge operation, this recovery value prevents it.

3 (SRV_FORCE_NO_TRX_UNDO)
Does not run transaction rollbacks after crash recovery.

4 (SRV_FORCE_NO_IBUF_MERGE)
Prevents insert buffer merge operations. If they would cause a crash, does not do them. Does not calculate table statistics. This value can permanently corrupt data files. After using this value, be prepared to drop and recreate all secondary indexes. Sets InnoDB to read-only.

5 (SRV_FORCE_NO_UNDO_LOG_SCAN)
Does not look at undo logs when starting the database: InnoDB treats even incomplete transactions as committed. This value can permanently corrupt data files. Sets InnoDB to read-only.

6 (SRV_FORCE_NO_LOG_REDO)
Does not do the redo log roll-forward in connection with recovery. This value can permanently corrupt data files. Leaves database pages in an obsolete state, which in turn may introduce more corruption into B-trees and other database structures. Sets InnoDB to read-only.

Finally, after troubleshooting, restore the "innodb_force_recovery" configuration to level 0 and then restart the database service to keep the system working properly.

Also note that this is only a workaround, it may also fail if the data is badly corrupted. Our advice remains that every database system should always have a mechanism to automatically back up data.


Sunday, 21 August 2022

[Flutter] Async Function vs Normal Function in Dart, How do they work?

 "Synchronous", "asynchronous", "await" and "asynchronous functions" are very confusing concepts when used in Flutter. For ease of explanation, in this article we will analyze two types of Flutter functions: Normal Function and Async Function. We will learn how these two types of functions work.

Ficture 1: Flutter/Dart async work flow

Normal Function and Async Function

The Dart language that Flutter uses inherits many features from Javascript. Dart's handling of synchronous and asynchronous jobs is also very similar to Javascript. There are two types of functions in the Dart language:

* Normal Function:

A function in Dart is declared as follows:


String doSomthing(){
    print('This is a normal Function');
    // do somthing
    return 'Done!';
}

* Async Function:

Async functions are functions declared with the async keyword at the end. 


String getApiContent() async{
    print('Async function loading api from Server');
    final response = await http.get(Uri.parse('https://codesiri.com/search/?q=api'));
    return response.body;
}
The difference of Async functions from normal functions is that in an Async function you will be able to use the await keyword to wait for another function to finish executing. Also, an Async doesn't return an immediate result, it just returns a Future.

Dart is an asynchronous language

By default, Dart always tries to process everything asynchronously whether it is an async function or a normal function. Let's analyze the example depicted in Figure 1.

Like other programming languages, DArt will also process the source code line by line from top to bottom. Even when encountering an Async function it continues to deal with the same logic. That's why in the example we see line 1 and line 2 in asyn function callApi still being executed. "Async" appears only when an actual async event occurs (http.get).

Inside an Async function when encountering a "real" async event (a predefined async event by Dart, not a self-created async function) there are 2 options.

Case 1: you can use the await keyword to wait until the async event completes and return the result. The current async function will break at that location. You did not read it wrong, Exactly, the async function will be interrupted at that point, not a new thread or process is initialized to run in the background at this time to continue the async task we are expecting. (You can use additional tools like Charles to verify this.) Of course Dart has kept in mind that there is an Async event still pending. Next Dart will return to the main program to continue to execute the next lines of code. That's why we see the sleep function being executed immediately followed by lines 3, 4, 5 being executed. After the main program has completed, Dart returns to continue processing asynchronous events and the next line of code in the async function.

Case 2: if you don't use await keyword before async event. Just like the case of 1 Dart will remember the pending asynchronous event, but next Dart will continue to execute the next code in the current async function as if nothing happened.


import 'package:http/http.dart' as http;
import 'dart:io';

void main(){	
  print('Line 1 - done !');
  var apiResult = callApi();
  sleep(Duration(seconds: 15)); // Test to monitor async task
  print('Line 3 - done !');
  normalFunction();
  print('Line 5 - done !');
}

Future callApi() async{
  print('Line 2 - Async Function callApi called');
  normalFunction2();
  print('==>A: Line 2 - Line 2 function callApi');
  final response = await http.get(Uri.parse('https://codesiri.com/search/?q=api'));
  print('==>A: Line 3 - call api done !');
  print('==>A: Line 4 - done !');
  return 'Done !';
}

void normalFunction1(){
  print('Line 4 - This is normalFunction1');
}
void normalFunction2(){
  print('==>A: Line 1 - This is normalFunction2');
}

Result:


I/flutter (21546): Line 1 - done !
I/flutter (21546): Line 2 - Async Function callApi called
I/flutter (21546): ==>A: Line 1 - This is normalFunction2
I/flutter (21546): ==>A: Line 2 - Line 2 function callApi
I/flutter (21546): Line 3 - done !
I/flutter (21546): Line 4 - This is normalFunction1
I/flutter (21546): Line 5 - done !
I/flutter (21546): ==>A: Line 3 - call api done !
I/flutter (21546): ==>A: Line 4 - done !

Dart is a single-threaded programming language

The reason Dart has to handle such complex asynchronous events is because it was designed to be a single-threaded language. By default our entire Flutter application runs on a single Dart thread. You will also still be able to create additional threads to actively handle parallel or background tasks, but then you will have to deal with the problems that arise.

Summary

When it encounters an async event, Dart will always push it to the bottom to wait for it to be processed. If there is await before the async call, all code that follows will also be pushed to the bottom to wait with it. Otherwise the next lines of code will still be treated as if nothing happened. Understanding how Dart's async works will help you optimize your application.