1% Licensed under the Apache License, Version 2.0 (the "License"); you may not 2% use this file except in compliance with the License. You may obtain a copy of 3% the License at 4% 5% http://www.apache.org/licenses/LICENSE-2.0 6% 7% Unless required by applicable law or agreed to in writing, software 8% distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9% WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10% License for the specific language governing permissions and limitations under 11% the License. 12 13-module(couch_db_engine). 14 15 16-include("couch_db.hrl"). 17-include("couch_db_int.hrl"). 18 19 20-type filepath() :: iolist(). 21-type docid() :: binary(). 22-type rev() :: {non_neg_integer(), binary()}. 23-type revs() :: [rev()]. 24-type json() :: any(). 25-type uuid() :: binary(). 26-type purge_seq() :: non_neg_integer(). 27 28-type doc_pair() :: { 29 #full_doc_info{} | not_found, 30 #full_doc_info{} | not_found 31 }. 32 33-type doc_pairs() :: [doc_pair()]. 34 35-type db_open_options() :: [ 36 create 37 ]. 38 39-type delete_options() :: [ 40 {context, delete | compaction} | 41 sync 42 ]. 43 44-type purge_info() :: {purge_seq(), uuid(), docid(), revs()}. 45-type epochs() :: [{Node::atom(), UpdateSeq::non_neg_integer()}]. 46-type size_info() :: [{Name::atom(), Size::non_neg_integer()}]. 47-type partition_info() :: [ 48 {partition, Partition::binary()} | 49 {doc_count, DocCount::non_neg_integer()} | 50 {doc_del_count, DocDelCount::non_neg_integer()} | 51 {sizes, size_info()} 52]. 53 54-type write_stream_options() :: [ 55 {buffer_size, Size::pos_integer()} | 56 {encoding, atom()} | 57 {compression_level, non_neg_integer()} 58 ]. 59 60-type doc_fold_options() :: [ 61 {start_key, Key::any()} | 62 {end_key, Key::any()} | 63 {end_key_gt, Key::any()} | 64 {dir, fwd | rev} | 65 include_reductions | 66 include_deleted 67 ]. 68 69-type changes_fold_options() :: [ 70 {dir, fwd | rev} 71 ]. 72 73-type purge_fold_options() :: [ 74 {start_key, Key::any()} | 75 {end_key, Key::any()} | 76 {end_key_gt, Key::any()} | 77 {dir, fwd | rev} 78 ]. 79 80-type db_handle() :: any(). 81 82-type doc_fold_fun() :: fun((#full_doc_info{}, UserAcc::any()) -> 83 {ok, NewUserAcc::any()} | 84 {stop, NewUserAcc::any()}). 85 86-type local_doc_fold_fun() :: fun((#doc{}, UserAcc::any()) -> 87 {ok, NewUserAcc::any()} | 88 {stop, NewUserAcc::any()}). 89 90-type changes_fold_fun() :: fun((#doc_info{}, UserAcc::any()) -> 91 {ok, NewUserAcc::any()} | 92 {stop, NewUserAcc::any()}). 93 94-type purge_fold_fun() :: fun((purge_info(), UserAcc::any()) -> 95 {ok, NewUserAcc::any()} | 96 {stop, NewUserAcc::any()}). 97 98 99% This is called by couch_server to determine which 100% engine should be used for the given database. DbPath 101% is calculated based on the DbName and the configured 102% extension for a given engine. The first engine to 103% return true is the engine that will be used for the 104% database. 105-callback exists(DbPath::filepath()) -> boolean(). 106 107 108% This is called by couch_server to delete a database. It 109% is called from inside the couch_server process which 110% means that the storage engine does not have to guarantee 111% its own consistency checks when executing in this 112% context. Although since this is executed in the context 113% of couch_server it should return relatively quickly. 114-callback delete( 115 RootDir::filepath(), 116 DbPath::filepath(), 117 DelOpts::delete_options()) -> 118 ok | {error, Reason::atom()}. 119 120 121% This function can be called from multiple contexts. It 122% will either be called just before a call to delete/3 above 123% or when a compaction is cancelled which executes in the 124% context of a couch_db_updater process. It is intended to 125% remove any temporary files used during compaction that 126% may be used to recover from a failed compaction swap. 127-callback delete_compaction_files( 128 RootDir::filepath(), 129 DbPath::filepath(), 130 DelOpts::delete_options()) -> 131 ok. 132 133 134% This is called from the couch_db_updater:init/1 context. As 135% such this means that it is guaranteed to only have one process 136% executing for a given DbPath argument (ie, opening a given 137% database is guaranteed to only happen in a single process). 138% However, multiple process may be trying to open different 139% databases concurrently so if a database requires a shared 140% resource that will require concurrency control at the storage 141% engine layer. 142% 143% The returned DbHandle should be a term that can be freely 144% copied between processes and accessed concurrently. However 145% its guaranteed that the handle will only ever be mutated 146% in a single threaded context (ie, within the couch_db_updater 147% process). 148-callback init(DbPath::filepath(), db_open_options()) -> 149 {ok, DbHandle::db_handle()}. 150 151 152% This is called in the context of couch_db_updater:terminate/2 153% and as such has the same properties for init/2. It's guaranteed 154% to be consistent for a given database but may be called by many 155% databases concurrently. 156-callback terminate(Reason::any(), DbHandle::db_handle()) -> Ignored::any(). 157 158 159% This is called in the context of couch_db_updater:handle_call/3 160% for any message that is unknown. It can be used to handle messages 161% from asynchronous processes like the engine's compactor if it has one. 162-callback handle_db_updater_call(Msg::any(), DbHandle::db_handle()) -> 163 {reply, Resp::any(), NewDbHandle::db_handle()} | 164 {stop, Reason::any(), Resp::any(), NewDbHandle::db_handle()}. 165 166 167% This is called in the context of couch_db_updater:handle_info/2 168% and has the same properties as handle_call/3. 169-callback handle_db_updater_info(Msg::any(), DbHandle::db_handle()) -> 170 {noreply, NewDbHandle::db_handle()} | 171 {noreply, NewDbHandle::db_handle(), Timeout::timeout()} | 172 {stop, Reason::any(), NewDbHandle::db_handle()}. 173 174 175% These functions are called by any process opening or closing 176% a database. As such they need to be able to handle being 177% called concurrently. For example, the legacy engine uses these 178% to add monitors to the main engine process. 179-callback incref(DbHandle::db_handle()) -> {ok, NewDbHandle::db_handle()}. 180-callback decref(DbHandle::db_handle()) -> ok. 181-callback monitored_by(DbHande::db_handle()) -> [pid()]. 182 183 184% This is called in the context of couch_db_updater:handle_info/2 185% and should return the timestamp of the last activity of 186% the database. If a storage has no notion of activity or the 187% value would be hard to report its ok to just return the 188% result of os:timestamp/0 as this will just disable idle 189% databases from automatically closing. 190-callback last_activity(DbHandle::db_handle()) -> erlang:timestamp(). 191 192 193% All of the get_* functions may be called from many 194% processes concurrently. 195 196% The database should make a note of the update sequence when it 197% was last compacted. If the database doesn't need compacting it 198% can just hard code a return value of 0. 199-callback get_compacted_seq(DbHandle::db_handle()) -> 200 CompactedSeq::non_neg_integer(). 201 202 203% The number of documents in the database which have all leaf 204% revisions marked as deleted. 205-callback get_del_doc_count(DbHandle::db_handle()) -> 206 DelDocCount::non_neg_integer(). 207 208 209% This number is reported in the database info properties and 210% as such can be any JSON value. 211-callback get_disk_version(DbHandle::db_handle()) -> Version::json(). 212 213 214% The number of documents in the database that have one or more 215% leaf revisions not marked as deleted. 216-callback get_doc_count(DbHandle::db_handle()) -> DocCount::non_neg_integer(). 217 218 219% The epochs track which node owned the database starting at 220% a given update sequence. Each time a database is opened it 221% should look at the epochs. If the most recent entry is not 222% for the current node it should add an entry that will be 223% written the next time a write is performed. An entry is 224% simply a {node(), CurrentUpdateSeq} tuple. 225-callback get_epochs(DbHandle::db_handle()) -> Epochs::epochs(). 226 227 228% Get the current purge sequence known to the engine. This 229% value should be updated during calls to purge_docs. 230-callback get_purge_seq(DbHandle::db_handle()) -> purge_seq(). 231 232 233% Get the oldest purge sequence known to the engine 234-callback get_oldest_purge_seq(DbHandle::db_handle()) -> purge_seq(). 235 236 237% Get the purged infos limit. This should just return the last 238% value that was passed to set_purged_docs_limit/2. 239-callback get_purge_infos_limit(DbHandle::db_handle()) -> pos_integer(). 240 241 242% Get the revision limit. This should just return the last 243% value that was passed to set_revs_limit/2. 244-callback get_revs_limit(DbHandle::db_handle()) -> RevsLimit::pos_integer(). 245 246 247% Get the current security properties. This should just return 248% the last value that was passed to set_security/2. 249-callback get_security(DbHandle::db_handle()) -> SecProps::any(). 250 251 252% Get the current properties. 253-callback get_props(DbHandle::db_handle()) -> Props::[any()]. 254 255 256% This information is displayed in the database info poperties. It 257% should just be a list of {Name::atom(), Size::non_neg_integer()} 258% tuples that will then be combined across shards. Currently, 259% various modules expect there to at least be values for: 260% 261% file - Number of bytes on disk 262% 263% active - Theoretical minimum number of bytes to store this db on disk 264% which is used to guide decisions on compaction 265% 266% external - Number of bytes that would be required to represent the 267% contents outside of the database (for capacity and backup 268% planning) 269-callback get_size_info(DbHandle::db_handle()) -> SizeInfo::size_info(). 270 271 272% This returns the information for the given partition. 273% It should just be a list of {Name::atom(), Size::non_neg_integer()} 274% It returns the partition name, doc count, deleted doc count and two sizes: 275% 276% active - Theoretical minimum number of bytes to store this partition on disk 277% 278% external - Number of bytes that would be required to represent the 279% contents of this partition outside of the database 280-callback get_partition_info(DbHandle::db_handle(), Partition::binary()) -> 281 partition_info(). 282 283 284% The current update sequence of the database. The update 285% sequence should be incrememnted for every revision added to 286% the database. 287-callback get_update_seq(DbHandle::db_handle()) -> UpdateSeq::non_neg_integer(). 288 289 290% Whenever a database is created it should generate a 291% persistent UUID for identification in case the shard should 292% ever need to be moved between nodes in a cluster. 293-callback get_uuid(DbHandle::db_handle()) -> UUID::binary(). 294 295 296% These functions are only called by couch_db_updater and 297% as such are guaranteed to be single threaded calls. The 298% database should simply store these values somewhere so 299% they can be returned by the corresponding get_* calls. 300 301-callback set_revs_limit(DbHandle::db_handle(), RevsLimit::pos_integer()) -> 302 {ok, NewDbHandle::db_handle()}. 303 304 305-callback set_purge_infos_limit(DbHandle::db_handle(), Limit::pos_integer()) -> 306 {ok, NewDbHandle::db_handle()}. 307 308 309-callback set_security(DbHandle::db_handle(), SecProps::any()) -> 310 {ok, NewDbHandle::db_handle()}. 311 312 313% This function is only called by couch_db_updater and 314% as such is guaranteed to be single threaded calls. The 315% database should simply store provided property list 316% unaltered. 317 318-callback set_props(DbHandle::db_handle(), Props::any()) -> 319 {ok, NewDbHandle::db_handle()}. 320 321 322% Set the current update sequence of the database. The intention is to use this 323% when copying a database such that the destination update sequence should 324% match exactly the source update sequence. 325-callback set_update_seq( 326 DbHandle::db_handle(), 327 UpdateSeq::non_neg_integer()) -> 328 {ok, NewDbHandle::db_handle()}. 329 330 331% This function will be called by many processes concurrently. 332% It should return a #full_doc_info{} record or not_found for 333% every provided DocId in the order those DocId's appear in 334% the input. 335% 336% Traditionally this function will only return documents that 337% were present in the database when the DbHandle was retrieved 338% from couch_server. It is currently unknown what would break 339% if a storage engine deviated from that property. 340-callback open_docs(DbHandle::db_handle(), DocIds::[docid()]) -> 341 [#full_doc_info{} | not_found]. 342 343 344% This function will be called by many processes concurrently. 345% It should return a #doc{} record or not_found for every 346% provided DocId in the order they appear in the input. 347% 348% The same caveats around database snapshots from open_docs 349% apply to this function (although this function is called 350% rather less frequently so it may not be as big of an 351% issue). 352-callback open_local_docs(DbHandle::db_handle(), DocIds::[docid()]) -> 353 [#doc{} | not_found]. 354 355 356% This function will be called from many contexts concurrently. 357% The provided RawDoc is a #doc{} record that has its body 358% value set to the body value returned from write_doc_body/2. 359% 360% This API exists so that storage engines can store document 361% bodies externally from the #full_doc_info{} record (which 362% is the traditional approach and is recommended). 363-callback read_doc_body(DbHandle::db_handle(), RawDoc::doc()) -> 364 doc(). 365 366 367% This function will be called from many contexts concurrently. 368% If the storage engine has a purge_info() record for any of the 369% provided UUIDs, those purge_info() records should be returned. The 370% resulting list should have the same length as the input list of 371% UUIDs. 372-callback load_purge_infos(DbHandle::db_handle(), [uuid()]) -> 373 [purge_info() | not_found]. 374 375 376% This function is called concurrently by any client process 377% that is writing a document. It should accept a #doc{} 378% record and return a #doc{} record with a mutated body it 379% wishes to have written to disk by write_doc_body/2. 380% 381% This API exists so that storage engines can compress 382% document bodies in parallel by client processes rather 383% than forcing all compression to occur single threaded 384% in the context of the couch_db_updater process. 385-callback serialize_doc(DbHandle::db_handle(), Doc::doc()) -> 386 doc(). 387 388 389% This function is called in the context of a couch_db_updater 390% which means its single threaded for the given DbHandle. 391% 392% The returned #doc{} record should have its Body set to a value 393% that will be stored in the #full_doc_info{} record's revision 394% tree leaves which is passed to read_doc_body/2 above when 395% a client wishes to read a document. 396% 397% The BytesWritten return value is used to determine the number 398% of active bytes in the database which can is used to make 399% a determination of when to compact this database. 400-callback write_doc_body(DbHandle::db_handle(), Doc::doc()) -> 401 {ok, FlushedDoc::doc(), BytesWritten::non_neg_integer()}. 402 403 404% This function is called from the context of couch_db_updater 405% and as such is guaranteed single threaded for the given 406% DbHandle. 407% 408% This is probably the most complicated function in the entire 409% API due to a few subtle behavior requirements required by 410% CouchDB's storage model. 411% 412% The Pairs argument is a list of pairs (2-tuples) of 413% #full_doc_info{} records. The first element of the pair is 414% the #full_doc_info{} that exists on disk. The second element 415% is the new version that should be written to disk. There are 416% two basic cases that should be followed: 417% 418% 1. {not_found, #full_doc_info{}} - A new document was created 419% 2. {#full_doc_info{}, #full_doc_info{}} - A document was updated 420% 421% The cases are fairly straight forward as long as proper 422% accounting for moving entries in the update sequence are accounted 423% for. 424% 425% The LocalDocs variable is applied separately. Its important to 426% note for new storage engine authors that these documents are 427% separate because they should *not* be included as part of the 428% changes index for the database. 429% 430% Traditionally an invocation of write_doc_infos should be all 431% or nothing in so much that if an error occurs (or the VM dies) 432% then the database doesn't retain any of the changes. However 433% as long as a storage engine maintains consistency this should 434% not be an issue as it has never been a guarantee and the 435% batches are non-deterministic (from the point of view of the 436% client). 437-callback write_doc_infos( 438 DbHandle::db_handle(), 439 Pairs::doc_pairs(), 440 LocalDocs::[#doc{}]) -> 441 {ok, NewDbHandle::db_handle()}. 442 443 444% This function is called from the context of couch_db_updater 445% and as such is guaranteed single threaded for the given 446% DbHandle. 447% 448% Each doc_pair() is a 2-tuple of #full_doc_info{} records. The 449% first element of the pair is the #full_doc_info{} that exists 450% on disk. The second element is the new version that should be 451% written to disk. There are three basic cases that should be considered: 452% 453% 1. {#full_doc_info{}, #full_doc_info{}} - A document was partially purged 454% 2. {#full_doc_info{}, not_found} - A document was completely purged 455% 3. {not_found, not_found} - A no-op purge 456% 457% In case 1, non-tail-append engines may have to remove revisions 458% specifically rather than rely on compaction to remove them. Also 459% note that the new #full_doc_info{} will have a different update_seq 460% that will need to be reflected in the changes feed. 461% 462% In case 2 you'll notice is "purged completely" which 463% means it needs to be removed from the database including the 464% update sequence. 465% 466% In case 3 we just need to store the purge_info() to know that it 467% was processed even though it produced no changes to the database. 468% 469% The purge_info() tuples contain the purge_seq, uuid, docid and 470% revisions that were requested to be purged. This should be persisted 471% in such a way that we can efficiently load purge_info() by its UUID 472% as well as iterate over purge_info() entries in order of their PurgeSeq. 473-callback purge_docs(DbHandle::db_handle(), [doc_pair()], [purge_info()]) -> 474 {ok, NewDbHandle::db_handle()}. 475 476 477% This function should be called from a single threaded context and 478% should be used to copy purge infos from on database to another 479% when copying a database 480-callback copy_purge_infos(DbHandle::db_handle(), [purge_info()]) -> 481 {ok, NewDbHandle::db_handle()}. 482 483 484% This function is called in the context of couch_db_udpater and 485% as such is single threaded for any given DbHandle. 486% 487% This call is made periodically to ensure that the database has 488% stored all updates on stable storage. (ie, here is where you fsync). 489-callback commit_data(DbHandle::db_handle()) -> 490 {ok, NewDbHande::db_handle()}. 491 492 493% This function is called by multiple processes concurrently. 494% 495% This function along with open_read_stream are part of the 496% attachments API. For the time being I'm leaving these mostly 497% undocumented. There are implementations of this in both the 498% legacy btree engine as well as the alternative engine 499% implementations for the curious, however this is a part of the 500% API for which I'd like feed back. 501% 502% Currently an engine can elect to not implement these API's 503% by throwing the atom not_supported. 504-callback open_write_stream( 505 DbHandle::db_handle(), 506 Options::write_stream_options()) -> 507 {ok, pid()}. 508 509 510% See the documentation for open_write_stream 511-callback open_read_stream(DbHandle::db_handle(), StreamDiskInfo::any()) -> 512 {ok, {Module::atom(), ReadStreamState::any()}}. 513 514 515% See the documentation for open_write_stream 516-callback is_active_stream(DbHandle::db_handle(), ReadStreamState::any()) -> 517 boolean(). 518 519 520% This funciton is called by many processes concurrently. 521% 522% This function is called to fold over the documents in 523% the database sorted by the raw byte collation order of 524% the document id. For each document id, the supplied user 525% function should be invoked with the first argument set 526% to the #full_doc_info{} record and the second argument 527% set to the current user supplied accumulator. The return 528% value of the user function is a 2-tuple of {Go, NewUserAcc}. 529% The NewUserAcc value should then replace the current 530% user accumulator. If Go is the atom ok, iteration over 531% documents should continue. If Go is the atom stop, then 532% iteration should halt and the return value should be 533% {ok, NewUserAcc}. 534% 535% Possible options to this function include: 536% 537% 1. start_key - Start iteration at the provided key or 538% or just after if the key doesn't exist 539% 2. end_key - Stop iteration just after the provided key 540% 3. end_key_gt - Stop iteration prior to visiting the provided 541% key 542% 4. dir - The atom fwd or rev. This is to be able to iterate 543% over documents in reverse order. The logic for comparing 544% start_key, end_key, and end_key_gt are then reversed (ie, 545% when rev, start_key should be greater than end_key if the 546% user wishes to see results) 547% 5. include_reductions - This is a hack for _all_docs since 548% it currently relies on reductions to count an offset. This 549% is a terrible hack that will need to be addressed by the 550% API in the future. If this option is present the supplied 551% user function expects three arguments, where the first 552% argument is a #full_doc_info{} record, the second argument 553% is the current list of reductions to the left of the current 554% document, and the third argument is the current user 555% accumulator. The return value from the user function is 556% unaffected. However the final return value of the function 557% should include the final total reductions as the second 558% element of a 3-tuple. Like I said, this is a hack. 559% 6. include_deleted - By default deleted documents are not 560% included in fold_docs calls. However in some special 561% cases we do want to see them (as of now, just in couch_changes 562% during the design document changes optimization) 563% 564% Historically, if a process calls this function repeatedly it 565% would see the same results returned even if there were concurrent 566% updates happening. However there doesn't seem to be any instance of 567% that actually happening so a storage engine that includes new results 568% between invocations shouldn't have any issues. 569-callback fold_docs( 570 DbHandle::db_handle(), 571 UserFold::doc_fold_fun(), 572 UserAcc::any(), 573 doc_fold_options()) -> 574 {ok, LastUserAcc::any()}. 575 576 577% This function may be called by many processes concurrently. 578% 579% This should behave exactly the same as fold_docs/4 except that it 580% should only return local documents and the first argument to the 581% user function is a #doc{} record, not a #full_doc_info{}. 582-callback fold_local_docs( 583 DbHandle::db_handle(), 584 UserFold::local_doc_fold_fun(), 585 UserAcc::any(), 586 doc_fold_options()) -> 587 {ok, LastUserAcc::any()}. 588 589 590% This function may be called by many processes concurrently. 591% 592% This function is called to fold over the documents (not local 593% documents) in order of their most recent update. Each document 594% in the database should have exactly one entry in this sequence. 595% If a document is updated during a call to this function it should 596% not be included twice as that will probably lead to Very Bad Things. 597% 598% This should behave similarly to fold_docs/4 in that the supplied 599% user function should be invoked with a #full_doc_info{} record 600% as the first argument and the current user accumulator as the 601% second argument. The same semantics for the return value from the 602% user function should be handled as in fold_docs/4. 603% 604% The StartSeq parameter indicates where the fold should start 605% *after*. As in, if a change with a value of StartSeq exists in the 606% database it should not be included in the fold. 607% 608% The only option currently supported by the API is the `dir` 609% option that should behave the same as for fold_docs. 610-callback fold_changes( 611 DbHandle::db_handle(), 612 StartSeq::non_neg_integer(), 613 UserFold::changes_fold_fun(), 614 UserAcc::any(), 615 changes_fold_options()) -> 616 {ok, LastUserAcc::any()}. 617 618 619% This function may be called by many processes concurrently. 620% 621% This function is called to fold over purged requests in order of 622% their oldest purge (increasing purge_seq order) 623% 624% The StartPurgeSeq parameter indicates where the fold should start *after*. 625-callback fold_purge_infos( 626 DbHandle::db_handle(), 627 StartPurgeSeq::purge_seq(), 628 UserFold::purge_fold_fun(), 629 UserAcc::any(), 630 purge_fold_options()) -> 631 {ok, LastUserAcc::any()}. 632 633 634% This function may be called by many processes concurrently. 635% 636% This function is called to count the number of documents changed 637% since the given UpdateSeq (ie, not including the possible change 638% at exactly UpdateSeq). It is currently only used internally to 639% provide a status update in a replication's _active_tasks entry 640% to indicate how many documents are left to be processed. 641% 642% This is a fairly difficult thing to support in engine's that don't 643% behave exactly like a tree with efficient support for counting rows 644% between keys. As such returning 0 or even just the difference between 645% the current update sequence is possibly the best some storage engines 646% can provide. This may lead to some confusion when interpreting the 647% _active_tasks entry if the storage engine isn't accounted for by the 648% client. 649-callback count_changes_since( 650 DbHandle::db_handle(), 651 UpdateSeq::non_neg_integer()) -> 652 TotalChanges::non_neg_integer(). 653 654 655% This function is called in the context of couch_db_updater and as 656% such is guaranteed to be single threaded for the given DbHandle. 657% 658% If a storage engine requires compaction this is a trigger to start 659% it off. However a storage engine can do whatever it wants here. As 660% this is fairly engine specific there's not a lot guidance that is 661% generally applicable. 662% 663% When compaction is finished the compactor should use 664% gen_server:cast/2 to send a {compact_done, CompactEngine, CompactInfo} 665% message to the Parent pid provided. Currently CompactEngine 666% must be the same engine that started the compaction and CompactInfo 667% is an arbitrary term that's passed to finish_compaction/4. 668-callback start_compaction( 669 DbHandle::db_handle(), 670 DbName::binary(), 671 Options::db_open_options(), 672 Parent::pid()) -> 673 {ok, NewDbHandle::db_handle(), CompactorPid::pid()}. 674 675 676% This function is called in the context of couch_db_udpater and as 677% such is guarnateed to be single threaded for the given DbHandle. 678% 679% Same as for start_compaction, this will be extremely specific to 680% any given storage engine. 681% 682% The split in the API here is so that if the storage engine needs 683% to update the DbHandle state of the couch_db_updater it can as 684% finish_compaction/4 is called in the context of the couch_db_updater. 685-callback finish_compaction( 686 OldDbHandle::db_handle(), 687 DbName::binary(), 688 Options::db_open_options(), 689 CompactInfo::any()) -> 690 {ok, CompactedDbHandle::db_handle(), CompactorPid::pid() | undefined}. 691 692 693-export([ 694 exists/2, 695 delete/4, 696 delete_compaction_files/4, 697 698 init/3, 699 terminate/2, 700 handle_db_updater_call/3, 701 handle_db_updater_info/2, 702 703 incref/1, 704 decref/1, 705 monitored_by/1, 706 707 last_activity/1, 708 709 get_engine/1, 710 get_compacted_seq/1, 711 get_del_doc_count/1, 712 get_disk_version/1, 713 get_doc_count/1, 714 get_epochs/1, 715 get_purge_seq/1, 716 get_oldest_purge_seq/1, 717 get_purge_infos_limit/1, 718 get_revs_limit/1, 719 get_security/1, 720 get_props/1, 721 get_size_info/1, 722 get_partition_info/2, 723 get_update_seq/1, 724 get_uuid/1, 725 726 set_revs_limit/2, 727 set_security/2, 728 set_purge_infos_limit/2, 729 set_props/2, 730 731 set_update_seq/2, 732 733 open_docs/2, 734 open_local_docs/2, 735 read_doc_body/2, 736 load_purge_infos/2, 737 738 serialize_doc/2, 739 write_doc_body/2, 740 write_doc_infos/3, 741 purge_docs/3, 742 copy_purge_infos/2, 743 commit_data/1, 744 745 open_write_stream/2, 746 open_read_stream/2, 747 is_active_stream/2, 748 749 fold_docs/4, 750 fold_local_docs/4, 751 fold_changes/5, 752 fold_purge_infos/5, 753 count_changes_since/2, 754 755 start_compaction/1, 756 finish_compaction/2, 757 trigger_on_compact/1 758]). 759 760 761exists(Engine, DbPath) -> 762 Engine:exists(DbPath). 763 764 765delete(Engine, RootDir, DbPath, DelOpts) when is_list(DelOpts) -> 766 Engine:delete(RootDir, DbPath, DelOpts). 767 768 769delete_compaction_files(Engine, RootDir, DbPath, DelOpts) 770 when is_list(DelOpts) -> 771 Engine:delete_compaction_files(RootDir, DbPath, DelOpts). 772 773 774init(Engine, DbPath, Options) -> 775 case Engine:init(DbPath, Options) of 776 {ok, EngineState} -> 777 {ok, {Engine, EngineState}}; 778 Error -> 779 throw(Error) 780 end. 781 782 783terminate(Reason, #db{} = Db) -> 784 #db{engine = {Engine, EngineState}} = Db, 785 Engine:terminate(Reason, EngineState). 786 787 788handle_db_updater_call(Msg, _From, #db{} = Db) -> 789 #db{ 790 engine = {Engine, EngineState} 791 } = Db, 792 case Engine:handle_db_updater_call(Msg, EngineState) of 793 {reply, Resp, NewState} -> 794 {reply, Resp, Db#db{engine = {Engine, NewState}}}; 795 {stop, Reason, Resp, NewState} -> 796 {stop, Reason, Resp, Db#db{engine = {Engine, NewState}}} 797 end. 798 799 800handle_db_updater_info(Msg, #db{} = Db) -> 801 #db{ 802 name = Name, 803 engine = {Engine, EngineState} 804 } = Db, 805 case Engine:handle_db_updater_info(Msg, EngineState) of 806 {noreply, NewState} -> 807 {noreply, Db#db{engine = {Engine, NewState}}}; 808 {noreply, NewState, Timeout} -> 809 {noreply, Db#db{engine = {Engine, NewState}}, Timeout}; 810 {stop, Reason, NewState} -> 811 couch_log:error("DB ~s shutting down: ~p", [Name, Msg]), 812 {stop, Reason, Db#db{engine = {Engine, NewState}}} 813 end. 814 815 816incref(#db{} = Db) -> 817 #db{engine = {Engine, EngineState}} = Db, 818 {ok, NewState} = Engine:incref(EngineState), 819 {ok, Db#db{engine = {Engine, NewState}}}. 820 821 822decref(#db{} = Db) -> 823 #db{engine = {Engine, EngineState}} = Db, 824 Engine:decref(EngineState). 825 826 827monitored_by(#db{} = Db) -> 828 #db{engine = {Engine, EngineState}} = Db, 829 Engine:monitored_by(EngineState). 830 831 832last_activity(#db{} = Db) -> 833 #db{engine = {Engine, EngineState}} = Db, 834 Engine:last_activity(EngineState). 835 836 837get_engine(#db{} = Db) -> 838 #db{engine = {Engine, _}} = Db, 839 Engine. 840 841 842get_compacted_seq(#db{} = Db) -> 843 #db{engine = {Engine, EngineState}} = Db, 844 Engine:get_compacted_seq(EngineState). 845 846 847get_del_doc_count(#db{} = Db) -> 848 #db{engine = {Engine, EngineState}} = Db, 849 Engine:get_del_doc_count(EngineState). 850 851 852get_disk_version(#db{} = Db) -> 853 #db{engine = {Engine, EngineState}} = Db, 854 Engine:get_disk_version(EngineState). 855 856 857get_doc_count(#db{} = Db) -> 858 #db{engine = {Engine, EngineState}} = Db, 859 Engine:get_doc_count(EngineState). 860 861 862get_epochs(#db{} = Db) -> 863 #db{engine = {Engine, EngineState}} = Db, 864 Engine:get_epochs(EngineState). 865 866 867get_purge_seq(#db{} = Db) -> 868 #db{engine = {Engine, EngineState}} = Db, 869 Engine:get_purge_seq(EngineState). 870 871 872get_oldest_purge_seq(#db{} = Db) -> 873 #db{engine = {Engine, EngineState}} = Db, 874 Engine:get_oldest_purge_seq(EngineState). 875 876 877get_purge_infos_limit(#db{} = Db) -> 878 #db{engine = {Engine, EngineState}} = Db, 879 Engine:get_purge_infos_limit(EngineState). 880 881 882get_revs_limit(#db{} = Db) -> 883 #db{engine = {Engine, EngineState}} = Db, 884 Engine:get_revs_limit(EngineState). 885 886 887get_security(#db{} = Db) -> 888 #db{engine = {Engine, EngineState}} = Db, 889 Engine:get_security(EngineState). 890 891 892get_props(#db{} = Db) -> 893 #db{engine = {Engine, EngineState}} = Db, 894 Engine:get_props(EngineState). 895 896 897get_size_info(#db{} = Db) -> 898 #db{engine = {Engine, EngineState}} = Db, 899 Engine:get_size_info(EngineState). 900 901 902get_partition_info(#db{} = Db, Partition) -> 903 #db{engine = {Engine, EngineState}} = Db, 904 Engine:get_partition_info(EngineState, Partition). 905 906 907get_update_seq(#db{} = Db) -> 908 #db{engine = {Engine, EngineState}} = Db, 909 Engine:get_update_seq(EngineState). 910 911get_uuid(#db{} = Db) -> 912 #db{engine = {Engine, EngineState}} = Db, 913 Engine:get_uuid(EngineState). 914 915 916set_revs_limit(#db{} = Db, RevsLimit) -> 917 #db{engine = {Engine, EngineState}} = Db, 918 {ok, NewSt} = Engine:set_revs_limit(EngineState, RevsLimit), 919 {ok, Db#db{engine = {Engine, NewSt}}}. 920 921 922set_purge_infos_limit(#db{} = Db, PurgedDocsLimit) -> 923 #db{engine = {Engine, EngineState}} = Db, 924 {ok, NewSt} = Engine:set_purge_infos_limit(EngineState, PurgedDocsLimit), 925 {ok, Db#db{engine = {Engine, NewSt}}}. 926 927 928set_security(#db{} = Db, SecProps) -> 929 #db{engine = {Engine, EngineState}} = Db, 930 {ok, NewSt} = Engine:set_security(EngineState, SecProps), 931 {ok, Db#db{engine = {Engine, NewSt}}}. 932 933 934set_props(#db{} = Db, Props) -> 935 #db{engine = {Engine, EngineState}} = Db, 936 {ok, NewSt} = Engine:set_props(EngineState, Props), 937 {ok, Db#db{engine = {Engine, NewSt}}}. 938 939 940set_update_seq(#db{} = Db, UpdateSeq) -> 941 #db{engine = {Engine, EngineState}} = Db, 942 {ok, NewSt} = Engine:set_update_seq(EngineState, UpdateSeq), 943 {ok, Db#db{engine = {Engine, NewSt}}}. 944 945 946open_docs(#db{} = Db, DocIds) -> 947 #db{engine = {Engine, EngineState}} = Db, 948 Engine:open_docs(EngineState, DocIds). 949 950 951open_local_docs(#db{} = Db, DocIds) -> 952 #db{engine = {Engine, EngineState}} = Db, 953 Engine:open_local_docs(EngineState, DocIds). 954 955 956read_doc_body(#db{} = Db, RawDoc) -> 957 #db{engine = {Engine, EngineState}} = Db, 958 Engine:read_doc_body(EngineState, RawDoc). 959 960 961load_purge_infos(#db{} = Db, UUIDs) -> 962 #db{engine = {Engine, EngineState}} = Db, 963 Engine:load_purge_infos(EngineState, UUIDs). 964 965 966serialize_doc(#db{} = Db, #doc{} = Doc) -> 967 #db{engine = {Engine, EngineState}} = Db, 968 Engine:serialize_doc(EngineState, Doc). 969 970 971write_doc_body(#db{} = Db, #doc{} = Doc) -> 972 #db{engine = {Engine, EngineState}} = Db, 973 Engine:write_doc_body(EngineState, Doc). 974 975 976write_doc_infos(#db{} = Db, DocUpdates, LocalDocs) -> 977 #db{engine = {Engine, EngineState}} = Db, 978 {ok, NewSt} = Engine:write_doc_infos(EngineState, DocUpdates, LocalDocs), 979 {ok, Db#db{engine = {Engine, NewSt}}}. 980 981 982purge_docs(#db{} = Db, DocUpdates, Purges) -> 983 #db{engine = {Engine, EngineState}} = Db, 984 {ok, NewSt} = Engine:purge_docs( 985 EngineState, DocUpdates, Purges), 986 {ok, Db#db{engine = {Engine, NewSt}}}. 987 988 989copy_purge_infos(#db{} = Db, Purges) -> 990 #db{engine = {Engine, EngineState}} = Db, 991 {ok, NewSt} = Engine:copy_purge_infos( 992 EngineState, Purges), 993 {ok, Db#db{engine = {Engine, NewSt}}}. 994 995 996commit_data(#db{} = Db) -> 997 #db{engine = {Engine, EngineState}} = Db, 998 {ok, NewSt} = Engine:commit_data(EngineState), 999 {ok, Db#db{engine = {Engine, NewSt}}}. 1000 1001 1002open_write_stream(#db{} = Db, Options) -> 1003 #db{engine = {Engine, EngineState}} = Db, 1004 Engine:open_write_stream(EngineState, Options). 1005 1006 1007open_read_stream(#db{} = Db, StreamDiskInfo) -> 1008 #db{engine = {Engine, EngineState}} = Db, 1009 Engine:open_read_stream(EngineState, StreamDiskInfo). 1010 1011 1012is_active_stream(#db{} = Db, ReadStreamState) -> 1013 #db{engine = {Engine, EngineState}} = Db, 1014 Engine:is_active_stream(EngineState, ReadStreamState). 1015 1016 1017fold_docs(#db{} = Db, UserFun, UserAcc, Options) -> 1018 #db{engine = {Engine, EngineState}} = Db, 1019 Engine:fold_docs(EngineState, UserFun, UserAcc, Options). 1020 1021 1022fold_local_docs(#db{} = Db, UserFun, UserAcc, Options) -> 1023 #db{engine = {Engine, EngineState}} = Db, 1024 Engine:fold_local_docs(EngineState, UserFun, UserAcc, Options). 1025 1026 1027fold_changes(#db{} = Db, StartSeq, UserFun, UserAcc, Options) -> 1028 #db{engine = {Engine, EngineState}} = Db, 1029 Engine:fold_changes(EngineState, StartSeq, UserFun, UserAcc, Options). 1030 1031 1032fold_purge_infos(#db{} = Db, StartPurgeSeq, UserFun, UserAcc, Options) -> 1033 #db{engine = {Engine, EngineState}} = Db, 1034 Engine:fold_purge_infos( 1035 EngineState, StartPurgeSeq, UserFun, UserAcc, Options). 1036 1037 1038count_changes_since(#db{} = Db, StartSeq) -> 1039 #db{engine = {Engine, EngineState}} = Db, 1040 Engine:count_changes_since(EngineState, StartSeq). 1041 1042 1043start_compaction(#db{} = Db) -> 1044 #db{ 1045 engine = {Engine, EngineState}, 1046 name = DbName, 1047 options = Options 1048 } = Db, 1049 {ok, NewEngineState, Pid} = Engine:start_compaction( 1050 EngineState, DbName, Options, self()), 1051 {ok, Db#db{ 1052 engine = {Engine, NewEngineState}, 1053 compactor_pid = Pid 1054 }}. 1055 1056 1057finish_compaction(Db, CompactInfo) -> 1058 #db{ 1059 engine = {Engine, St}, 1060 name = DbName, 1061 options = Options 1062 } = Db, 1063 NewDb = case Engine:finish_compaction(St, DbName, Options, CompactInfo) of 1064 {ok, NewState, undefined} -> 1065 couch_event:notify(DbName, compacted), 1066 Db#db{ 1067 engine = {Engine, NewState}, 1068 compactor_pid = nil 1069 }; 1070 {ok, NewState, CompactorPid} when is_pid(CompactorPid) -> 1071 Db#db{ 1072 engine = {Engine, NewState}, 1073 compactor_pid = CompactorPid 1074 } 1075 end, 1076 ok = couch_server:db_updated(NewDb), 1077 {ok, NewDb}. 1078 1079 1080trigger_on_compact(DbName) -> 1081 {ok, DDocs} = get_ddocs(DbName), 1082 couch_db_plugin:on_compact(DbName, DDocs). 1083 1084 1085get_ddocs(<<"shards/", _/binary>> = DbName) -> 1086 {_, Ref} = spawn_monitor(fun() -> 1087 exit(fabric:design_docs(mem3:dbname(DbName))) 1088 end), 1089 receive 1090 {'DOWN', Ref, _, _, {ok, JsonDDocs}} -> 1091 {ok, lists:map(fun(JsonDDoc) -> 1092 couch_doc:from_json_obj(JsonDDoc) 1093 end, JsonDDocs)}; 1094 {'DOWN', Ref, _, _, Else} -> 1095 Else 1096 end; 1097get_ddocs(DbName) -> 1098 couch_util:with_db(DbName, fun(Db) -> 1099 FoldFun = fun(FDI, Acc) -> 1100 {ok, Doc} = couch_db:open_doc_int(Db, FDI, []), 1101 {ok, [Doc | Acc]} 1102 end, 1103 {ok, Docs} = couch_db:fold_design_docs(Db, FoldFun, [], []), 1104 {ok, lists:reverse(Docs)} 1105 end). 1106