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