{"id":11004,"date":"2018-03-03T22:26:16","date_gmt":"2018-03-03T21:26:16","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/"},"modified":"2018-03-03T22:26:16","modified_gmt":"2018-03-03T21:26:16","slug":"18c-new-lost-write-protection","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/","title":{"rendered":"18c new Lost Write Protection"},"content":{"rendered":"<h2>By Franck Pachot<\/h2>\n<p>.<br \/>\nThere are many layers between the Oracle Database pwrite() calls and the physical sector written on disk: filesystem, logical volume, SAN or NAS, with a lot of smart software running for Virtualisation, Compression, Snapshotting, Synchronisation&#8230; Are you sure that the changes you made to your data is actually persisted on disk, completely and without any corruption? In case of bug or crash in the storage layer, it may happen that only part of the changes was written. In the case of crash, Oracle ensures that the datafile headers are written at the end, so that recovery can kick-in after the crash. Then, a partially written block can be detected and restored. With different checksum settings, you can also check block integrity while writing or reading. But that protects only for fractured blocks. What if a block write just did not occur? An old version of the block remains and then is perfectly correct for checksum, RMAN, and DBV.<\/p>\n<p>You may be 100% sure that you have never experienced lost writes. But then I&#8217;ll ask you: how do you know it? You don&#8217;t. Except if you enable Lost Write Protection.<br \/>\n<!--more--><br \/>\nIn 11g Oracle introduced this feature for Data Guard configurations. Data Guard is the best protection as the synchronization is done at the highest level: the change vector, generated before any I\/O and block modification occurred. Do not use SAN synchronization for your database. Data Guard is less expensive (no option needed), more efficient (only the persistent change information is shipped), and protects over all layers. It protects from lost writes because blocks are written on both sites by a different server, instance, storage. And Data Guard can detect lost writes by shipping the block SCN for each read to compare it with the standby.<\/p>\n<p>However, this has an overhead: redo generation for reads. Oracle 18c comes with a new solution with no need for a standby database: a new LOST WRITE PROTECTION tablespace is created to store the SCN of each block modified.<\/p>\n<h3>Do you have lost writes?<\/h3>\n<p>First I&#8217;ll show what happens without this feature. I create a table filled with number, timestamp and SCN:<\/p>\n<pre><code>\nSQL&gt; create table DEMO.DEMO pctfree 99 as select rownum id,1 n, current_timestamp ts , (select current_scn from v$database) scn from xmltable('1 to 10');\nTable DEMO.DEMO created.\n&nbsp;\nSQL&gt; select owner,segment_name,segment_type,block_id,blocks,sum(blocks)over(partition by owner,segment_name,segment_type) from dba_extents where owner='DEMO' and segment_name='DEMO' order by 1,2,3,4;\n&nbsp;\nOWNER   SEGMENT_NAME   SEGMENT_TYPE     BLOCK_ID   BLOCKS   SUM(BLOCKS)OVER(PARTITIONBYOWNER,SEGMENT_NAME,SEGMENT_TYPE)\n-----   ------------   ------------     --------   ------   -----------------------------------------------------------\nDEMO    DEMO           TABLE                3128        8                                                             8\n&nbsp;\nSQL&gt; column block_id new_value last_block_id\nSQL&gt; select dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO;\n&nbsp;\n  BLOCK_ID   ID   N TS                                                    SCN\n  --------   --   - --                                                    ---\n      3131    1   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3131    2   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3132    3   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3132    4   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3133    5   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3133    6   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3134    7   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3134    8   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3135    9   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3135   10   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n&nbsp;\nSQL&gt; column block_id clear\n<\/code><\/pre>\n<p>I&#8217;ve recorded the las BLOCK_ID in &amp;last_block_id and ensures that all those modifications are written on dosk:<\/p>\n<pre><code>\nSQL&gt; alter system checkpoint;\nSystem CHECKPOINT altered.\n&nbsp;\nSQL&gt; alter system flush buffer_cache;\nSystem FLUSH altered.\n<\/code><\/pre>\n<p>I save the block 3133 to keep an old version of it. This will be my way to simulate a lost write.<\/p>\n<pre><code>\nSQL&gt; host dd if=\/u01\/oradata\/CDB1\/PDB1\/users01.dbf of=\/var\/tmp\/lwp.blk skip=$(( &amp;last_block_id - 2 )) bs=8k count=1\n1+0 records in\n1+0 records out\n8192 bytes (8.2 kB) copied, 0.000263416 s, 31.1 MB\/s\n<\/code><\/pre>\n<p>Now, I update all rows, set new timestamp, SCN and increase the number 1 to 2.<\/p>\n<pre><code>\nSQL&gt; update DEMO.DEMO set n=2+1, ts=current_timestamp, scn=(select current_scn from v$database);\n10 rows updated.\nSQL&gt; commit;\nCommit complete.\n&nbsp;\nSQL&gt; alter system checkpoint;\nSystem CHECKPOINT altered.\nSQL&gt; alter system flush buffer_cache;\nSystem FLUSH altered.\n<\/code><\/pre>\n<p>Here is how I reproduce lost writes. All blocks changed were written to disk, but I restore the old version of block 3133 as if this one was not written:<\/p>\n<pre><code>\nSQL&gt; host dd if=\/var\/tmp\/lwp.blk of=\/u01\/oradata\/CDB1\/PDB1\/users01.dbf seek=$(( &amp;last_block_id - 2 )) bs=8k count=1 conv=notrunc\n1+0 records in\n1+0 records out\n8192 bytes (8.2 kB) copied, 0.000111582 s, 73.4 MB\/s\n<\/code><\/pre>\n<p>This is what you can see if one of your storage layers missed a write and nevertheless acknowledged the I\/O call.<\/p>\n<pre><code>s\nSQL&gt; select dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO;\n  BLOCK_ID   ID   N TS                                                    SCN\n  --------   --   - ---------------------------------------------     -------\n      3131    1   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n      3131    2   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n      3132    3   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n      3132    4   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n      3133    5   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3133    6   1 03-MAR-18 04.51.37.838991000 PM EUROPE\/ZURICH     4619734\n      3134    7   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n      3134    8   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n      3135    9   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n      3135   10   3 03-MAR-18 04.51.39.255582000 PM EUROPE\/ZURICH     4619806\n<\/code><\/pre>\n<p>No errors. No corruption. Just old values for the rows in this block. And there&#8217;s no way to detect it. Physical reads, RMAN, DBV, will all see a perfectly correct block. Only if those changes are inconsistent with other tables (with constraints) or indexes, you may detect a logical corruption.<\/p>\n<p>The probability that this problem occurs is very low (a storage bug on exactly one 8k block or multiple of it). But it is critical because it cannot be detected. To detect it, you need to compare the full block or a checksum, or simply the SCN with another copy, such as in the standby database. Or, with this new feature, store the SCN of each data block in a new structure: the 18c LOST WRITE DETECTION.<\/p>\n<h3>Enabling Lost Write Protection<\/h3>\n<p>You need to create a tablespace to store those SCN. There&#8217;s no choice you must use a bigfile tablespace, but you can create multiple small ones if you want.<\/p>\n<pre><code>\nSQL&gt; create bigfile tablespace SHADOW\n  2   datafile '\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf'\n  3   size 5M\n  4   lost write protection;\n&nbsp;\nTablespace SHADOW created.\n&nbsp;\nSQL&gt; select tablespace_name,status,bigfile,contents,logging,allocation_type,encrypted,lost_write_protect,chunk_tablespace from dba_tablespaces;\nTABLESPACE_NAME   STATUS   BIGFILE   CONTENTS                LOGGING     ALLOCATION_TYPE   ENCRYPTED   LOST_WRITE_PROTECT   CHUNK_TABLESPACE\n---------------   ------   -------   --------                -------     ---------------   ---------   ------------------   ----------------\nSYSTEM            ONLINE   NO        PERMANENT               LOGGING     SYSTEM            NO          OFF                  N\nSYSAUX            ONLINE   NO        PERMANENT               LOGGING     SYSTEM            NO          OFF                  N\nUNDOTBS1          ONLINE   NO        UNDO                    LOGGING     SYSTEM            NO          OFF                  N\nTEMP              ONLINE   NO        TEMPORARY               NOLOGGING   UNIFORM           NO          OFF                  N\nSHADOW            ONLINE   YES       LOST WRITE PROTECTION   LOGGING     SYSTEM            NO          OFF                  N\nUSERS             ONLINE   NO        PERMANENT               LOGGING     SYSTEM            NO          OFF                  N\n&nbsp;\nSQL&gt; select * from dba_data_files;\n&nbsp;\nFILE_NAME                                FILE_ID TABLESPACE_NAME         BYTES   BLOCKS STATUS        RELATIVE_FNO AUTOEXTENSIBLE        MAXBYTES   MAXBLOCKS   INCREMENT_BY   USER_BYTES   USER_BLOCKS ONLINE_STATUS   LOST_WRITE_PROTECT\n---------                                ------- ---------------         -----   ------ ------        ------------ --------------        --------   ---------   ------------   ----------   ----------- -------------   ------------------\n\/u01\/oradata\/CDB1\/PDB1\/undotbs01.dbf         164 UNDOTBS1            104857600    12800 AVAILABLE                9 YES                34359721984     4194302            640    103809024         12672 ONLINE          OFF\n\/u01\/oradata\/CDB1\/PDB1\/sysaux01.dbf          163 SYSAUX              408944640    49920 AVAILABLE                4 YES                34359721984     4194302           1280    407896064         49792 ONLINE          OFF\n\/u01\/oradata\/CDB1\/PDB1\/system01.dbf          162 SYSTEM              272629760    33280 AVAILABLE                1 YES                34359721984     4194302           1280    271581184         33152 SYSTEM          OFF\n\/u01\/oradata\/CDB1\/PDB1\/users01.dbf           169 USERS               104857600    12800 AVAILABLE              169 NO                           0           0              0    103809024         12672 ONLINE          OFF\n\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf             58 SHADOW                5242880      640 AVAILABLE             1024 NO                           0           0              0      4194304           512 ONLINE          OFF\n<\/code><\/pre>\n<p>Then you enable this feature for the database (or pluggable database) and for the tablespaces you want to protect:<\/p>\n<pre><code>\nSQL&gt; alter pluggable database enable lost write protection;\nPluggable database ENABLE altered.\n&nbsp;\nSQL&gt; alter tablespace USERS enable lost write protection;\nTablespace USERS altered.\n<\/code><\/pre>\n<p>Here are the new columns in DBA_TABLESPACES and DBA_DATA_FILES:<\/p>\n<pre><code>\nSQL&gt; select tablespace_name,status,bigfile,contents,logging,allocation_type,encrypted,lost_write_protect,chunk_tablespace from dba_tablespaces;\n&nbsp;\nTABLESPACE_NAME   STATUS   BIGFILE   CONTENTS                LOGGING     ALLOCATION_TYPE   ENCRYPTED   LOST_WRITE_PROTECT   CHUNK_TABLESPACE\n---------------   ------   -------   --------                -------     ---------------   ---------   ------------------   ----------------\nSYSTEM            ONLINE   NO        PERMANENT               LOGGING     SYSTEM            NO          OFF                  N\nSYSAUX            ONLINE   NO        PERMANENT               LOGGING     SYSTEM            NO          OFF                  N\nUNDOTBS1          ONLINE   NO        UNDO                    LOGGING     SYSTEM            NO          OFF                  N\nTEMP              ONLINE   NO        TEMPORARY               NOLOGGING   UNIFORM           NO          OFF                  N\nSHADOW            ONLINE   YES       LOST WRITE PROTECTION   LOGGING     SYSTEM            NO          OFF                  N\nUSERS             ONLINE   NO        PERMANENT               LOGGING     SYSTEM            NO          ENABLED              N\n&nbsp;\nSQL&gt; select * from dba_data_files;\n&nbsp;\nFILE_NAME                                FILE_ID TABLESPACE_NAME         BYTES   BLOCKS STATUS        RELATIVE_FNO AUTOEXTENSIBLE        MAXBYTES   MAXBLOCKS   INCREMENT_BY   USER_BYTES   USER_BLOCKS ONLINE_STATUS   LOST_WRITE_PROTECT\n---------                                ------- ---------------         -----   ------ ------        ------------ --------------        --------   ---------   ------------   ----------   ----------- -------------   ------------------\n\/u01\/oradata\/CDB1\/PDB1\/undotbs01.dbf         164 UNDOTBS1            104857600    12800 AVAILABLE                9 YES                34359721984     4194302            640    103809024         12672 ONLINE          OFF\n\/u01\/oradata\/CDB1\/PDB1\/sysaux01.dbf          163 SYSAUX              408944640    49920 AVAILABLE                4 YES                34359721984     4194302           1280    407896064         49792 ONLINE          OFF\n\/u01\/oradata\/CDB1\/PDB1\/system01.dbf          162 SYSTEM              272629760    33280 AVAILABLE                1 YES                34359721984     4194302           1280    271581184         33152 SYSTEM          OFF\n\/u01\/oradata\/CDB1\/PDB1\/users01.dbf           169 USERS               104857600    12800 AVAILABLE              169 NO                           0           0              0    103809024         12672 ONLINE          ENABLED\n\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf             58 SHADOW                5242880      640 AVAILABLE             1024 NO                           0           0              0      4194304           512 ONLINE          OFF\n<\/code><\/pre>\n<p>Note that we are on the Oracle Cloud here and all tablespaces must be encrypted. This is also the case with the LOST WRITE PROTECTION one. Here you can see ENCRYPTION at none only because I decrypted them to look at what is inside the files. <\/p>\n<p>Here are some internal tables giving some information about the storage. Note that tablespace number TSID=7 here is USERS, the one protected, and the TSID=6 one is the LOST WRITE PROTECTION one.<\/p>\n<pre><code>\nSQL&gt; select * from new_lost_write_datafiles$;\n&nbsp;\n  DATAFILE_TSID_TRACKED   DATAFILE_RFN_TRACKED   SHADOW_DATAFILE_TSID   SHADOW_DATAFILE_RFN   SHADOW_DATAFILE_OFFSET   NUMBER_OF_BLOCKS_ALLOCATED DATAFILE_CURRENT_STATUS\n  ---------------------   --------------------   --------------------   -------------------   ----------------------   -------------------------- -----------------------\n                      7                    169                      6                  1024                      128                          184 enabled\n&nbsp;\nSQL&gt; select * from new_lost_write_extents$;\n&nbsp;\n  EXTENT_DATAFILE_RFN   EXTENT_DATAFILE_TSID   EXTENT_START   EXTENT_LENGTH_BLOCKS_2K   EXTENT_NEXT_BLOCK\n  -------------------   --------------------   ------------   -----------------------   -----------------\n                 1024                      6            312                      1312                 641\n&nbsp;\nSQL&gt; select * from new_lost_write_shadows$;\n&nbsp;\n  SHADOW_DATAFILE_RFN   SHADOW_DATAFILE_TSID   SHADOW_NUMBER_BLOCKS_ALLOC   SHADOW_FIRST_FREE_BLOCK   SHADOW_BLOCK_SIZE_BYTES   SHADOW_RECS_PER_BLOCK\n  -------------------   --------------------   --------------------------   -----------------------   -----------------------   ---------------------\n                 1024                      6                          640                       128                      8192                     136\n<\/code><\/pre>\n<p>Because there was already a &#8216;lost write&#8217; feature, this one is called &#8216;new lost write&#8217;.<\/p>\n<p>NEW_LOST_WRITE_DATAFILE$ lists all protected (aka tracked) datafiles with the LOST WRITE PROTECTION (aka shadow) tablespace protecting it. The status can be &#8216;enabled&#8217; or &#8216;suspended&#8217;. The row is deleted if the protection is removed.<\/p>\n<p>NEW_LOST_WRITE_SHADOWS$ lists the LOST WRITE PROTECTION tablespaces. It contains a 1MB bitmap in the first 128 blocks, and extents starts after this.<\/p>\n<p>NEW_LOST_WRITE_EXTENTS$ maps the free extents in the shadow tablespace. Here, the lost write protection for my USERS tablespace (100MB) takes 312 &#8211; 128 = 184 blocks (1.4 MB). The extent is 4MB. The 1312 EXTENT_LENGTH_BLOCKS_2K are the remaining free space in the extent, in 2KB blocks. 4MB-1.4MB=2.6MB which is 1312 x 2k blocks.<\/p>\n<h3>Simulate Lost Write<\/h3>\n<p>As I did before, I create a DEMO table<\/p>\n<pre><code>\nSQL&gt; create table DEMO.DEMO pctfree 99 as select rownum id,1 n, current_timestamp ts , (select current_scn from v$database) scn from xmltable('1 to 10');\nTable DEMO.DEMO created.\n&nbsp;\nSQL&gt; column block_id new_value last_block_id\nSQL&gt; select dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO;\n  BLOCK_ID   ID   N TS                                                    SCN\n  --------   --   - ---------------------------------------------     -------\n      3123    1   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3123    2   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3124    3   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3124    4   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3125    5   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3125    6   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3126    7   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3126    8   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3127    9   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n      3127   10   1 03-MAR-18 04.21.00.797975000 PM EUROPE\/ZURICH     4578079\n<\/code><\/pre>\n<p>I save one block:<\/p>\n<pre><code>\nSQL&gt; column block_id clear\nSQL&gt; alter system checkpoint;\nSystem CHECKPOINT altered.\nSQL&gt; alter system flush buffer_cache;\nSystem FLUSH altered.\nSQL&gt; host dd if=\/u01\/oradata\/CDB1\/PDB1\/users01.dbf of=\/var\/tmp\/lwp.blk skip=$(( &amp;last_block_id - 2 )) bs=8k count=1\n1+0 records in\n1+0 records out\n8192 bytes (8.2 kB) copied, 0.000325309 s, 25.2 MB\/s\n<\/code><\/pre>\n<p>Update the table:<\/p>\n<pre><code>\nSQL&gt; update DEMO.DEMO set n=2+1, ts=current_timestamp, scn=(select current_scn from v$database);\n10 rows updated.\nSQL&gt; commit;\nCommit complete.\nSQL&gt; alter system checkpoint;\nSystem CHECKPOINT altered.\nSQL&gt; alter system flush buffer_cache;\nSystem FLUSH altered.\n<\/code><\/pre>\n<p>Write back the block I saved, to simulate a lost write:<\/p>\n<pre><code>\nSQL&gt; host dd if=\/var\/tmp\/lwp.blk of=\/u01\/oradata\/CDB1\/PDB1\/users01.dbf seek=$(( &amp;last_block_id - 2 )) bs=8k count=1 conv=notrunc\n1+0 records in\n1+0 records out\n8192 bytes (8.2 kB) copied, 0.000104103 s, 78.7 MB\/s\n<\/code><\/pre>\n<h3>Lost Write detection<\/h3>\n<p>Now, when I query the table, the lost write is detected and an error is raised:<\/p>\n<pre><code>\nSQL&gt; select dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO;\n&nbsp;\nError starting at line : 93 File @ \/media\/sf_share\/18c\/lost_write_protection.sql\nIn command -\nselect dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO\nError report -\nORA-65478: shadow lost write protection - found lost write\n<\/code><\/pre>\n<p>In the alert.log I have the mention of the block that failed:<\/p>\n<pre><code>\n2018-03-03 16:21:06.842000 +01:00\nERROR - I\/O type:buffered I\/O found lost write in block with file#:169 rdba:0x2a400c35, Expected SCN:0x000000000045db54 SCN in block:0x000000000045db23, approx current SCN:0x000000000045dbbb, RAC instance:1 pdb:5\n*****************************************************************\nAn internal routine has requested a dump of selected redo.\nThis usually happens following a specific internal error, when\nanalysis of the redo logs will help Oracle Support with the\ndiagnosis.\nIt is recommended that you retain all the redo logs generated (by\nall the instances) during the past 12 hours, in case additional\nredo dumps are required to help with the diagnosis.\n*****************************************************************\n<\/code><\/pre>\n<p>The block defined by the RDBA in alert.log is the one I have manually corrupted:<\/p>\n<pre><code>\nSQL&gt; select dbms_utility.data_block_address_file(to_number('2a400c35','XXXXXXXX'))file#,dbms_utility.data_block_address_block( to_number('2a400c35','XXXXXXXX'))block# from dual;\n&nbsp;\n     FILE#     BLOCK#\n---------- ----------\n       169       3125\n<\/code><\/pre>\n<p>As mentioned in the alert.log the session has dumped the redo, as found in the session trace file:<\/p>\n<pre><code>\nALTER SYSTEM DUMP REDO DBA MIN 169 3125 DBA MAX 169 3125 SCN MIN 4578132 SCN MAX 4578235 CON_ID 5\n<\/code><\/pre>\n<p>This SCN 4578132 is the commit SCN for my update. And the 4578235 is the current one. I can see the change that was lost here: <\/p>\n<pre><code>\nCHANGE #10 CON_ID:5 TYP:0 CLS:1 AFN:169 DBA:0x2a400c35 OBJ:73527 SCN:0x000000000045db23 SEQ:2 OP:11.4 ENC:0 RBL:0 FLG:0x0000\nKTB Redo\nop: 0x01  ver: 0x01\ncompat bit: 4 (post-11) padding: 1\nop: F  xid:  0x0008.019.000002d6    uba: 0x02401257.01a2.24\nKDO Op code: LKR row dependencies Disabled\n  xtype: XA flags: 0x00000000  bdba: 0x2a400c35  hdba: 0x2a400c32\nitli: 2  ispac: 0  maxfr: 4858\ntabn: 0 slot: 0 to: 2\nCHANGE #11 CON_ID:5 TYP:0 CLS:1 AFN:169 DBA:0x2a400c35 OBJ:73527 SCN:0x000000000045db54 SEQ:1 OP:11.5 ENC:0 RBL:0 FLG:0x0000\nKTB Redo\nop: 0x02  ver: 0x01\ncompat bit: 4 (post-11) padding: 1\nop: C  uba: 0x02401257.01a2.25\nKDO Op code: URP row dependencies Disabled\n  xtype: XAxtype KDO_KDOM2 flags: 0x00000080  bdba: 0x2a400c35  hdba: 0x2a400c32\nitli: 2  ispac: 0  maxfr: 4858\ntabn: 0 slot: 0(0x0) flag: 0x2c lock: 2 ckix: 0\nncol: 4 nnew: 3 size: 0\nVector content:\ncol  1: [ 2]  c1 04\ncol  2: [13]  78 76 03 03 10 16 02 0d 73 cd 48 86 58\ncol  3: [ 5]  c4 05 3a 52 20\n<\/code><\/pre>\n<h3>Then we need to recover&#8230;<\/h3>\n<p>However, unfortunately, this block is not marked as corrupt:<\/p>\n<pre><code>\nSQL&gt; select * from  V$DATABASE_BLOCK_CORRUPTION;\nno rows selected\n<\/code><\/pre>\n<p>This means that I cannot use RMAN block recovery:<\/p>\n<pre><code>\nSQL&gt; host rman target \/ &lt;&lt;\nStarting recover at 03-MAR-18\nusing target database control file instead of recovery catalog\nallocated channel: ORA_DISK_1\nchannel ORA_DISK_1: SID=152 device type=DISK\nallocated channel: ORA_DISK_2\n&nbsp;\nstarting media recovery\nmedia recovery complete, elapsed time: 00:00:00\n&nbsp;\nFinished recover at 03-MAR-18\n<\/code><\/pre>\n<p>And the RMAN recovery advisor is not aware of the problem:<\/p>\n<pre><code>\nRMAN&gt; list failure;\n&nbsp;\nusing target database control file instead of recovery catalog\nDatabase Role: PRIMARY\n&nbsp;\nno failures found that match specification\n<\/code><\/pre>\n<p>So the solution is to mark it as corrupt or restore the whole datafile (or section). And maybe ensure that the write was lost on the data, and not on the lost write tracking block itself. The redo dump may help for that.<\/p>\n<h3>strace: additional I\/Os<\/h3>\n<p>I traced the server process to see what files are read during my query:<\/p>\n<pre><code>\nSQL&gt; column spid new_value pid\nSQL&gt; select spid from v$process join v$session on v$session.paddr=v$process.addr where sid=sys_context('userenv','sid');\nSPID\n9360\nSQL&gt; column spid clear\nSQL&gt; define bg=&amp;:\nSQL&gt; host strace -p &amp;pid -o strace.txt &amp;bg\n<\/code><\/pre>\n<p>This small awk filters I\/O calls on users01.dbf and shadow.dbf and displays the system calls on the file handle<\/p>\n<pre><code>\nawk '\/open[(][\"].*(shadow.dbf|users01.dbf).*[\"],\/{l=$0;gsub(\/[(,)]\/,\" \");h[$NF]=$2\" \"$NF;print $l;$0=$l}\/^[a-zA-Z0-9]+[(][0-9]+[,)]\/{l=$0;gsub(\/[(,)]\/,\" \"); if ( $1 == \"close\" ) h[$2]=\"\" ; if ( h[$2]!=\"\" ) printf \"%-130s t%80sn\",l,h[$2]}\/F_DUPFD\/{if ( h[$2]!=\"\" ) h[$NF]=h[$2]\" \"$NF;h[$2]=\"\"}' strace.txt | grep --color=auto -E \"^|^.*users01.*\"\n<\/code><\/pre>\n<p>Here are the open() and pread() calls:<\/p>\n<pre><code>\nopen \"\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf\"  O_RDWR|O_DSYNC  = 8\nfcntl(8, F_SETFD, FD_CLOEXEC)           = 0                                                             \"\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf\" 8\nfcntl(8, F_DUPFD, 256)                  = 256                                                           \"\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf\" 8\nfcntl(256, F_SETFD, FD_CLOEXEC)         = 0                                                         \"\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf\" 8 256\npread64(256, \"X242226V333E1f372366\"..., 8192, 1056768) = 8192                                \"\/u01\/oradata\/CDB1\/PDB1\/shadow.dbf\" 8 256\nopen \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\"  O_RDWR|O_DSYNC  = 8\nfcntl(8, F_SETFD, FD_CLOEXEC)           = 0                                                            \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8\nfcntl(8, F_DUPFD, 256)                  = 257                                                          \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8\nfcntl(257, F_SETFD, FD_CLOEXEC)         = 0                                                        \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\npread64(257, \"#242002f@*%333E14370264\"..., 8192, 25575424) = 8192                           \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\npread64(257, \"6242003f@*T333E56317H1007371!333E\"..., 40960, 25583616) = 40960           \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\npread64(257, \"6242005f@*#333E24zo1007371!333E\"..., 8192, 25600000) = 8192                \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\npread64(257, \"6242003f@*T333E56317H1007371!333E\"..., 40960, 25583616) = 40960           \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\npread64(257, \"6242005f@*#333E24zo1007371!333E\"..., 8192, 25600000) = 8192                \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\npread64(257, \"6242003f@*T333E56317H1007371!333E\"..., 40960, 25583616) = 40960           \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\npread64(257, \"6242005f@*#333E24zo1007371!333E\"..., 8192, 25600000) = 8192                \"\/u01\/oradata\/CDB1\/PDB1\/users01.dbf\" 8 257\n<\/code><\/pre>\n<p>We can see the lost write protection file read first (1 block at offset 1056768 which is block 129, the first one after the 1MB header) and the SCNs for my 5 blocks table are all there. Then the table blocks are read. Note that all those blocks (lost protection and data) goes into the buffer cache, and then do not have to be re-read each time. Here, I&#8217;ve run my failing select 3 times and only the first one had to read the shadow datafile.<\/p>\n<h3>X$BH: additional buffer gets<\/h3>\n<p>As those blocks are read through the buffer cache during the consistent reads, I checked the buffer cache headers for the 3 times I&#8217;ve run the queries. I&#8217;ve identified them from the function that reads them: kcbr_lost_get_lost_write_scns<\/p>\n<pre><code>\nSQL&gt; select dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO;\nORA-65478: shadow lost write protection - found lost write\n&nbsp;\nSQL&gt; select obj,state,tch,fp_whr from x$bh where fp_whr like 'kr_gcur_4: kcbr_lost_get_lost_w%';\n&nbsp;\n         OBJ   STATE   TCH FP_WHR\n         ---   -----   --- ------\n  4294967295       1     1 kr_gcur_4: kcbr_lost_get_lost_w\n&nbsp;\n&nbsp;\nSQL&gt; select dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO;\nORA-65478: shadow lost write protection - found lost write\n&nbsp;\nSQL&gt; select obj,state,tch,fp_whr from x$bh where fp_whr like 'kr_gcur_4: kcbr_lost_get_lost_w%';\n&nbsp;\n         OBJ   STATE   TCH FP_WHR\n         ---   -----   --- ------\n  4294967295       1     2 kr_gcur_4: kcbr_lost_get_lost_w\n&nbsp;\n&nbsp;\nSQL&gt; select dbms_rowid.rowid_block_number(rowid) block_id,DEMO.* from DEMO.DEMO;\nORA-65478: shadow lost write protection - found lost write\n&nbsp;\nSQL&gt; select obj,state,tch,fp_whr from x$bh where fp_whr like 'kr_gcur_4: kcbr_lost_get_lost_w%';\n&nbsp;\n         OBJ   STATE   TCH FP_WHR\n         ---   -----   --- ------\n  4294967295       1     3 kr_gcur_4: kcbr_lost_get_lost_w\n<\/code><\/pre>\n<p>Here we can see the touch count increasing. It seems that for each query the kcbr_lost_get_lost_write_scns is called, even when there was no modification and no new read from disk.<\/p>\n<p>While we&#8217;re there, let&#8217;s breakpoint on this fonction to see when it is called:<\/p>\n<pre><code>\n(gdb) break kcbr_lost_get_lost_write_scns\nBreakpoint 1 at 0x85a9140\n(gdb) c\nContinuing.\n&nbsp;\nBreakpoint 1, 0x00000000085a9140 in kcbr_lost_get_lost_write_scns ()\n(gdb) bt\n#0  0x00000000085a9140 in kcbr_lost_get_lost_write_scns ()\n#1  0x0000000001cf9c01 in kcbzibmlt ()\n#2  0x0000000001ce2f29 in kcbzib ()\n#3  0x0000000011e7f6e9 in kcbgtcr ()\n#4  0x0000000011e366bd in ktrget2 ()\n#5  0x00000000121d5ca7 in kdst_fetch0 ()\n#6  0x00000000121e4f5a in kdstf000110100000000km ()\n#7  0x00000000121d398e in kdsttgr ()\n#8  0x000000001224d28f in qertbFetch ()\n#9  0x00000000120340ef in opifch2 ()\n#10 0x0000000002d8d033 in kpoal8 ()\n#11 0x000000001203af9c in opiodr ()\n#12 0x000000001230acf7 in ttcpip ()\n#13 0x00000000026a5667 in opitsk ()\n#14 0x00000000026aa27d in opiino ()\n#15 0x000000001203af9c in opiodr ()\n#16 0x00000000026a10a3 in opidrv ()\n#17 0x00000000032a58af in sou2o ()\n#18 0x0000000000d68047 in opimai_real ()\n#19 0x00000000032b2667 in ssthrdmain ()\n#20 0x0000000000d67e53 in main ()\n<\/code><\/pre>\n<p>Look at <a href=\"https:\/\/fritshoogland.wordpress.com\/2017\/10\/16\/oracle-c-functions-annotations\/\" target=\"_blank\" rel=\"noopener noreferrer\">Frits Hoogland annotations<\/a> for the signification and you will see that this is called during consistent reads -&gt; input buffer.<\/p>\n<h3>So what?<\/h3>\n<p>This feature is interesting. Of course, we need to measure the overhead of this detection, but this additional storage of the SCN being implemented as any data block, benefits from all its efficiency: buffer cache, background writes by dbwr, protection by redo, backups,&#8230; These times, I see more and more databases installed on storage with fancy features, and admins playing with snapshot without really knowing whether it is consistent or not. This is the opposite of the &#8216;reliable&#8217; and &#8216;keep it simple&#8217; properties that we want for our data. For these environments, when I cannot convince the storage admins to forget about those features and rely on Data Guard on top of the simplest storage, then at least we have a way to protect us from failures in those layers.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>By Franck Pachot . There are many layers between the Oracle Database pwrite() calls and the physical sector written on disk: filesystem, logical volume, SAN or NAS, with a lot of smart software running for Virtualisation, Compression, Snapshotting, Synchronisation&#8230; Are you sure that the changes you made to your data is actually persisted on disk, [&hellip;]<\/p>\n","protected":false},"author":27,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[59],"tags":[221,1310,96,1184],"type_dbi":[],"class_list":["post-11004","post","type-post","status-publish","format-standard","hentry","category-oracle","tag-data-guard","tag-lost-write","tag-oracle","tag-oracle-18c"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.2 (Yoast SEO v27.2) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>18c new Lost Write Protection - dbi Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"18c new Lost Write Protection\" \/>\n<meta property=\"og:description\" content=\"By Franck Pachot . There are many layers between the Oracle Database pwrite() calls and the physical sector written on disk: filesystem, logical volume, SAN or NAS, with a lot of smart software running for Virtualisation, Compression, Snapshotting, Synchronisation&#8230; Are you sure that the changes you made to your data is actually persisted on disk, [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2018-03-03T21:26:16+00:00\" \/>\n<meta name=\"author\" content=\"Oracle Team\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Oracle Team\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"18 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/\"},\"author\":{\"name\":\"Oracle Team\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/66ab87129f2d357f09971bc7936a77ee\"},\"headline\":\"18c new Lost Write Protection\",\"datePublished\":\"2018-03-03T21:26:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/\"},\"wordCount\":1456,\"commentCount\":0,\"keywords\":[\"Data Guard\",\"Lost Write\",\"Oracle\",\"Oracle 18c\"],\"articleSection\":[\"Oracle\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/\",\"name\":\"18c new Lost Write Protection - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\"},\"datePublished\":\"2018-03-03T21:26:16+00:00\",\"author\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/66ab87129f2d357f09971bc7936a77ee\"},\"breadcrumb\":{\"@id\":\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\/\/www.dbi-services.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"18c new Lost Write Protection\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#website\",\"url\":\"https:\/\/www.dbi-services.com\/blog\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/66ab87129f2d357f09971bc7936a77ee\",\"name\":\"Oracle Team\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/secure.gravatar.com\/avatar\/f711f7cd2c9b09bf2627133755b569fb5be0694810cfd33033bdd095fedba86d?s=96&d=mm&r=g\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/f711f7cd2c9b09bf2627133755b569fb5be0694810cfd33033bdd095fedba86d?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/f711f7cd2c9b09bf2627133755b569fb5be0694810cfd33033bdd095fedba86d?s=96&d=mm&r=g\",\"caption\":\"Oracle Team\"},\"url\":\"https:\/\/www.dbi-services.com\/blog\/author\/oracle-team\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"18c new Lost Write Protection - dbi Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/","og_locale":"en_US","og_type":"article","og_title":"18c new Lost Write Protection","og_description":"By Franck Pachot . There are many layers between the Oracle Database pwrite() calls and the physical sector written on disk: filesystem, logical volume, SAN or NAS, with a lot of smart software running for Virtualisation, Compression, Snapshotting, Synchronisation&#8230; Are you sure that the changes you made to your data is actually persisted on disk, [&hellip;]","og_url":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/","og_site_name":"dbi Blog","article_published_time":"2018-03-03T21:26:16+00:00","author":"Oracle Team","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Oracle Team","Est. reading time":"18 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/"},"author":{"name":"Oracle Team","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/66ab87129f2d357f09971bc7936a77ee"},"headline":"18c new Lost Write Protection","datePublished":"2018-03-03T21:26:16+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/"},"wordCount":1456,"commentCount":0,"keywords":["Data Guard","Lost Write","Oracle","Oracle 18c"],"articleSection":["Oracle"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/","url":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/","name":"18c new Lost Write Protection - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2018-03-03T21:26:16+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/66ab87129f2d357f09971bc7936a77ee"},"breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/18c-new-lost-write-protection\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"18c new Lost Write Protection"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/66ab87129f2d357f09971bc7936a77ee","name":"Oracle Team","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/f711f7cd2c9b09bf2627133755b569fb5be0694810cfd33033bdd095fedba86d?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/f711f7cd2c9b09bf2627133755b569fb5be0694810cfd33033bdd095fedba86d?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/f711f7cd2c9b09bf2627133755b569fb5be0694810cfd33033bdd095fedba86d?s=96&d=mm&r=g","caption":"Oracle Team"},"url":"https:\/\/www.dbi-services.com\/blog\/author\/oracle-team\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/11004","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/27"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=11004"}],"version-history":[{"count":0,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/11004\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=11004"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=11004"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=11004"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=11004"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}