WL#9141: InnoDB: Refactor uncompressed BLOB code to facilitate partial fetch/update

Affects: Server-8.0   —   Status: Complete

Introduction:
=============
    
This is a sub worklog of "WL#8960 InnoDB: Partial Fetch and Update of BLOB".
This worklog is the second sub worklog followed by "WL#8985 InnoDB: Refactor
compressed BLOB code to facilitate partial fetch/update". The purpose of this
worklog is to refactor current code so that new BLOB features can be added
conveniently.  This worklog does to uncompressed BLOB similar to what WL#8985
did to compressed BLOB code.
    
Logical Changes:
================
    
.  The functionality of uncompressed BLOB is provided by C-style functions.
   This will be converted to C++ classes, structs and member functions.
.  The BLOB code will be isolated and kept in lob0lob.h and lob0lob.cc files.
   This will help in modular development of BLOB features.
.  All references will now be LOB (large objects).

Detailed Changes:
=================

. Introduced new module named lob.  It contains lob/lob0lob.cc and
  include/lob0lob.h files.
. Added new namespace lob.
. lob::Inserter - a new class to insert a complete uncompressed BLOB.
. lob::zInserter - a new class to insert a complete compressed BLOB.
. lob::InsertContext - a new class to contain contextual information for the
   insert operation.
. lob::BaseInserter - a class that holds common state and functions useful
   for both compressed and uncompressed BLOB.  This is the base class for
   lob::Inserter and lob::zInserter.
. lob::Deleter - a new class to destory/delete a BLOB
  (both compressed/uncompressed)
. lob::DeleteContext - a new class to contain contextual information for the
  delete operation
. lob::Reader - a new class to fetch a uncompressed BLOB.
. lob::zReader - a new class to fetch a compressed BLOB.
. lob::ReaderContext - a new class to contain contextual information for the
   fetch operation

Design Rationale:
=================

There are 2 approaches that I explored - one is to have a single LOB class with
each major operations as an member function.  For example,

class LOB {
public:
   int insert();
   int update();
   int read();
   // ..
private:
   // ...
   Context* m_ctx;
};

But doing it this way, will make the class LOB like a kitchen sink.  It will
end up that some member variables are used only when we are doing insert
operation, and some other member variables are used when doing read operation
and so on.  There won't be any cohesion b/w the member variables and member
functions.  For one instance of the LOB class, we will most likely use only one
operation, eg insert.  This is the reason I didn't prefer this approach.  The
other approach is to design LOB classes around the major operations that will
be performed, which truely reflects the way these classes will be used. 

The current design of LOB classes revolves around the way the major operations
that will be performed on LOB data.  The currently supported major operations
are insert, delete and read.  As of now all of them operate on complete LOB
data.  For each of the major operation one new class is introduced.

Inserter - for inserting LOB data.
Reader   - for reading LOB data.
Deleter  - for deleting LOB data.

Now there are two variants to LOB data - compressed and uncompressed.  An
insert operation or a read operation is completely depended on whether the data
is compressed or not. But a delete operation is not that much dependant on
this. Hence I introduced separate classes for compressed LOB.

Inserter - for inserting uncompressed LOB data.
zInserter - for inserting compressed LOB data.
Reader   - for reading uncompressed LOB data.
zReader   - for reading compressed LOB data.
Deleter  - for deleting both compressed and uncompressed LOB data.

At this point I noticed that there was some common code between Inserter and
zInserter which I can factor out into a base class.  So I introduced
BaseInserter which will contain common state and function useful for both
Inserter and zInserter.  So the final list of main LOB classes are:

Inserter - for inserting uncompressed LOB data.
zInserter - for inserting compressed LOB data.
BaseInserter - a base class containing common state and functions useful for
                   both Inserter and zInserter.  Inserter and zInserter derives
                   from this base class.
Reader   - for reading uncompressed LOB data.
zReader   - for reading compressed LOB data.
Deleter  - for deleting both compressed and uncompressed LOB data.

One point to be noted is that these classes are formed by refactoring existing
code.  So to reduce the amount of code changes, I allowed some differences in
the way they operate.  The Inserter and zInserter class is designed to insert
all the LOB data of a single clustered index record.  It operates on the big
record vector.  But the other classes (Reader, Deleter, zReader) all operate
on a single LOB data only.  By doing it this way, I avoid significant amount
of code changes.  

The main classes of the LOB module has been identified above.  To support them
there was a need to provide context classes that will contain information needed
for LOB operation.  Previously, the C style functions had a list of 6 or 7
arguments.  These arguments are the context information that is necessary to 
provide
the various main operations on LOB data.  For each main operation, the context
information is identified separately.  They are as follows:

InsertContext - context information for doing insert of LOB. `
DeleteContext - context information for doing delete of LOB. `
ReadContext   - context information for doing fetch of LOB. `

The insert operation also has one special optimization - the bulk insert.
These context classes evolved separately as I refactored one operation at a
time.  And when I look back, I don't see any need to club them all together.
There are some specific checks that are done only for the insert operation,
like the redo log space check, which are captured in the InsertContext.  If
we have a single context class, then it will contain unnecessary information
not usable for the current operation.  Also, all these context classes are
arrived at based on how and where it will be used.

Finally, while evaluating this design, please do keep in mind that these
classes come out of refactoring existing code.  If you look at the patch, the
amount of code changed where LOB module is _used_ is very minimal.  I think my
main focus was to isolate the LOB code and design a set of C++ classes which
will make the extension of functionality easier. 

And the main purpose of refactoring was to enable to add partial fetch and
partial modify/update operations.  For these purposes, I believe that this
design is suitable.  Surely one can do more and more refactoring to achieve
better results.  But since we are doing refactoring for a particular purpose, I
think we should stop when our purpose will be solved.

Functions Removed:
==================

The following functions has been removed.

. btr_copy_blob_prefix()
. btr_copy_externally_stored_field_prefix_low_func()

Functions Moved to lob module:
==============================

The following functions are moved to the lob module.

. btr_copy_externally_stored_field_prefix_func() and the associated
  macros.
. btr_rec_free_updated_extern_fields()
. btr_blob_get_part_len()
. btr_blob_get_next_page_no() 
. btr_check_blob_fil_page_type() 
. btr_rec_free_externally_stored_fields()
. btr_copy_externally_stored_field_prefix_func()
. btr_copy_externally_stored_field_func()
There is no functionality changes done in this worklog.  There are no functional
and non-functional requirements.  Just ensure that there are no performance
regressions because of this code refactoring.
This worklog will isolate the LOB code into a separate module.  The following
will be the interface to make use of LOB.

lob::Inserter - a class to insert uncompressed large object (LOB).
lob::Reader   - a class to fetch uncompressed LOB.
lob::Deleter  - a class to free/delete both compressed/uncompressed LOB.
lob::zInserter - a class to insert compressed LOB.
lob::zReader  - a class to fetch compressed LOB.

For each of the LOB operations described above there is an associated context
object.  They are listed here:

lob::InserterContext - a context object for insert operation.
lob::ReaderContext - a context object for fetch/read operation.
lob::DeleterContext - a context object for delete/free operation.

A new namespace lob has been introduced that enclose all large object (LOB)
classes, structs, enums and functions.