@@ -92,10 +92,10 @@ static blb* store_array(thread_db*, jrd_tra*, bid*);
9292
9393namespace {
9494
95- class ReplaceDataHelper
95+ class DataModifyHelper
9696{
9797public:
98- ReplaceDataHelper (thread_db* tdbb, const vcl* blb_pages, const offset_t position, const void * buffer, const ULONG length) :
98+ DataModifyHelper (thread_db* tdbb, const vcl* blb_pages, const offset_t position, const void * buffer, const ULONG length) :
9999 m_newData (buffer), m_newLength(length),
100100 m_level1Pages (*blb_pages),
101101 m_pageDataLength (tdbb->getDatabase ()->dbb_page_size - BLP_SIZE)
@@ -1645,6 +1645,21 @@ void blb::BLB_put_data(thread_db* tdbb, const UCHAR* buffer, SLONG length)
16451645 SET_TDBB (tdbb);
16461646 const BLOB_PTR * p = buffer;
16471647
1648+ // BLB_put_segment will remove the flag after teh first call so replace the data here
1649+ if (blb_flags & BLB_seek)
1650+ {
1651+ if (!(blb_flags & BLB_temporary) || (blb_flags & BLB_closed))
1652+ ERR_post (Arg::Gds (isc_cannot_update_old_blob));
1653+
1654+ blb_flags &= ~BLB_seek;
1655+
1656+ // Modify part inside existing data
1657+ if (modifyDataMoveBuffer (tdbb, blb_seek, p, length))
1658+ return ;
1659+
1660+ // Continue and append the rest
1661+ }
1662+
16481663 while (length > 0 )
16491664 {
16501665 // ASF: the comment below was copied from BLB_get_data
@@ -1679,6 +1694,17 @@ void blb::BLB_put_segment(thread_db* tdbb, const void* seg, USHORT segment_lengt
16791694 if (!(blb_flags & BLB_temporary) || (blb_flags & BLB_closed))
16801695 ERR_post (Arg::Gds (isc_cannot_update_old_blob));
16811696
1697+ if (blb_flags & BLB_seek)
1698+ {
1699+ blb_flags &= ~BLB_seek;
1700+
1701+ // Modify part inside existing data
1702+ if (modifyDataMoveBuffer (tdbb, blb_seek, segment, segment_length))
1703+ return ;
1704+
1705+ // Continue and append the rest
1706+ }
1707+
16821708 if (blb_filter)
16831709 {
16841710 BLF_put_segment (tdbb, &blb_filter, segment_length, segment);
@@ -2016,6 +2042,95 @@ void blb::scalar(thread_db* tdbb,
20162042 blob->BLB_close (tdbb);
20172043}
20182044
2045+ void blb::modifyExistingData (thread_db* tdbb, offset_t position, const void * buffer, const ULONG length)
2046+ {
2047+ fb_assert ((blb_flags & BLB_temporary) && !(blb_flags & BLB_closed));
2048+
2049+ const offset_t end = position + length;
2050+ fb_assert (end <= blb_length);
2051+
2052+ if (blb_level == 0 )
2053+ {
2054+ blob_page* page = (blob_page*) getBuffer ();
2055+ memcpy (reinterpret_cast <char *>(page->blp_page ) + position, buffer, length);
2056+ return ;
2057+ }
2058+
2059+ DataModifyHelper helper (tdbb, blb_pages, position, buffer, length);
2060+ blob_page* page = nullptr ;
2061+
2062+ WIN window (blb_pg_space_id, -1 );
2063+ if (blb_flags & BLB_large_scan)
2064+ {
2065+ window.win_flags = WIN_large_scan;
2066+ window.win_scans = 1 ;
2067+ }
2068+
2069+ auto releasePage = [&tdbb, &window](const bool mark)
2070+ {
2071+ if (mark)
2072+ CCH_MARK (tdbb, &window);
2073+
2074+ if (window.win_flags & WIN_large_scan)
2075+ CCH_RELEASE_TAIL (tdbb, &window);
2076+ else
2077+ CCH_RELEASE (tdbb, &window);
2078+ };
2079+
2080+ // Level 1 blobs are much easier -- page number is in vector.
2081+ if (blb_level == 1 )
2082+ {
2083+ while (helper.needWrite ())
2084+ {
2085+ if (!helper.hasPages ()) // The last data is in the blb_buffer
2086+ {
2087+ page = reinterpret_cast <blob_page*>(getBuffer ());
2088+ helper.replaceInPage (page);
2089+ fb_assert (helper.getWrittenLength () == length);
2090+ return ;
2091+ }
2092+
2093+ // Level 1 page constains data
2094+ window.win_page = helper.getNextLevel1PageId ();
2095+ page = reinterpret_cast <blob_page*>(CCH_FETCH (tdbb, &window, LCK_write, pag_blob));
2096+ helper.replaceInPage (page);
2097+ releasePage (true );
2098+ }
2099+ }
2100+ else
2101+ {
2102+ auto level2page = helper.setLevel2 (blb_pointers);
2103+ while (helper.needWrite ())
2104+ {
2105+ if (!helper.hasPages ()) // The last data is in the blb_buffer
2106+ {
2107+ helper.replaceInPage (page);
2108+ fb_assert (helper.getWrittenLength () == length);
2109+ return ;
2110+ }
2111+
2112+ // Level 1 page contains pointers
2113+ window.win_page = helper.getNextLevel1PageId ();
2114+ page = reinterpret_cast <blob_page*>(CCH_FETCH (tdbb, &window, LCK_write, pag_blob));
2115+
2116+ // Level 2 pages contain data
2117+ const auto numberOfPagess = page->blp_length / sizeof (page->blp_page );
2118+ for (FB_SIZE_T i = level2page; i < numberOfPagess && helper.needWrite (); ++i)
2119+ {
2120+ auto level2Page = reinterpret_cast <blob_page*>(CCH_HANDOFF (tdbb, &window,
2121+ page->blp_page [i],
2122+ LCK_write, pag_blob));
2123+
2124+ helper.replaceInPage (level2Page);
2125+ CCH_MARK (tdbb, &window);
2126+ }
2127+ releasePage (false );
2128+
2129+ level2page = 0 ; // Offset only for the first pages
2130+ }
2131+ }
2132+ fb_assert (helper.getWrittenLength () == length);
2133+ }
20192134
20202135static ArrayField* alloc_array (jrd_tra* transaction, Ods::InternalArrayDesc* proto_desc)
20212136{
@@ -3106,102 +3221,14 @@ void blb::BLB_cancel()
31063221 BLB_cancel (JRD_get_thread_data ());
31073222}
31083223
3109- void blb::BLB_write (thread_db* tdbb, offset_t position, const void * buffer, const ULONG length)
3224+ void blb::BLB_write (thread_db* tdbb, offset_t position, const void * buffer, ULONG length)
31103225{
31113226 if (!(blb_flags & BLB_temporary) || (blb_flags & BLB_closed))
3112- ERR_post (Arg::Gds (isc_cannot_update_old_blob));
3113-
3114- if (position > blb_length)
3115- ERR_post (Arg::Gds (isc_blob_out_of_length_write) << Arg::Int64 (position) << Arg::Int64 (blb_length));
3116-
3117- const offset_t end = position + length;
3118- if (end > blb_length)
3119- {
3120- const offset_t middle = blb_length - position;
3121- BLB_write (tdbb, position, buffer, middle); // Replace
3122- BLB_put_segment (tdbb, (const UCHAR *)buffer + middle, length - middle); // Append
3123- return ;
3124- }
3125-
3126- if (blb_level == 0 )
3127- {
3128- blob_page* page = (blob_page*) getBuffer ();
3129- memcpy (reinterpret_cast <char *>(page->blp_page ) + position, buffer, length);
3130- return ;
3131- }
3132-
3133- ReplaceDataHelper helper (tdbb, blb_pages, position, buffer, length);
3134- blob_page* page = nullptr ;
3135-
3136- WIN window (blb_pg_space_id, -1 );
3137- if (blb_flags & BLB_large_scan)
3138- {
3139- window.win_flags = WIN_large_scan;
3140- window.win_scans = 1 ;
3141- }
3142-
3143- auto releasePage = [&tdbb, &window](const bool mark)
3144- {
3145- if (mark)
3146- CCH_MARK (tdbb, &window);
3147-
3148- if (window.win_flags & WIN_large_scan)
3149- CCH_RELEASE_TAIL (tdbb, &window);
3150- else
3151- CCH_RELEASE (tdbb, &window);
3152- };
3153-
3154- // Level 1 blobs are much easier -- page number is in vector.
3155- if (blb_level == 1 )
3156- {
3157- while (helper.needWrite ())
3158- {
3159- if (!helper.hasPages ()) // The last data is in the blb_buffer
3160- {
3161- page = reinterpret_cast <blob_page*>(getBuffer ());
3162- helper.replaceInPage (page);
3163- fb_assert (helper.getWrittenLength () == length);
3164- return ;
3165- }
3227+ ERR_post (Arg::Gds (isc_cannot_update_old_blob)); // Cannot update existing blob
31663228
3167- // Level 1 page constains data
3168- window.win_page = helper.getNextLevel1PageId ();
3169- page = reinterpret_cast <blob_page*>(CCH_FETCH (tdbb, &window, LCK_write, pag_blob));
3170- helper.replaceInPage (page);
3171- releasePage (true );
3172- }
3173- }
3174- else
3175- {
3176- auto level2page = helper.setLevel2 (blb_pointers);
3177- while (helper.needWrite ())
3178- {
3179- if (!helper.hasPages ()) // The last data is in the blb_buffer
3180- {
3181- helper.replaceInPage (page);
3182- fb_assert (helper.getWrittenLength () == length);
3183- return ;
3184- }
3185-
3186- // Level 1 page contains pointers
3187- window.win_page = helper.getNextLevel1PageId ();
3188- page = reinterpret_cast <blob_page*>(CCH_FETCH (tdbb, &window, LCK_write, pag_blob));
3229+ // Modify part inside existing data
3230+ if (modifyDataMoveBuffer (tdbb, position, buffer, length))
3231+ return ; // Only modify, exit
31893232
3190- // Level 2 pages contain data
3191- const auto numberOfPagess = page->blp_length / sizeof (page->blp_page );
3192- for (FB_SIZE_T i = level2page; i < numberOfPagess && helper.needWrite (); ++i)
3193- {
3194- auto level2Page = reinterpret_cast <blob_page*>(CCH_HANDOFF (tdbb, &window,
3195- page->blp_page [i],
3196- LCK_write, pag_blob));
3197-
3198- helper.replaceInPage (level2Page);
3199- CCH_MARK (tdbb, &window);
3200- }
3201- releasePage (false );
3202-
3203- level2page = 0 ; // Offset only for the first pages
3204- }
3205- }
3206- fb_assert (helper.getWrittenLength () == length);
3233+ BLB_put_segment (tdbb, buffer, length); // Append
32073234}
0 commit comments