summaryrefslogtreecommitdiff
path: root/src/mongo/gotools/mongodump/metadata_dump.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/mongo/gotools/mongodump/metadata_dump.go')
-rw-r--r--src/mongo/gotools/mongodump/metadata_dump.go107
1 files changed, 107 insertions, 0 deletions
diff --git a/src/mongo/gotools/mongodump/metadata_dump.go b/src/mongo/gotools/mongodump/metadata_dump.go
new file mode 100644
index 00000000000..5a4382b6d2e
--- /dev/null
+++ b/src/mongo/gotools/mongodump/metadata_dump.go
@@ -0,0 +1,107 @@
+package mongodump
+
+import (
+ "bufio"
+ "fmt"
+ "github.com/mongodb/mongo-tools/common/bsonutil"
+ "github.com/mongodb/mongo-tools/common/db"
+ "github.com/mongodb/mongo-tools/common/intents"
+ "github.com/mongodb/mongo-tools/common/json"
+ "github.com/mongodb/mongo-tools/common/log"
+ "gopkg.in/mgo.v2/bson"
+)
+
+// Metadata holds information about a collection's options and indexes.
+type Metadata struct {
+ Options interface{} `json:"options,omitempty"`
+ Indexes []interface{} `json:"indexes"`
+}
+
+// IndexDocumentFromDB is used internally to preserve key ordering.
+type IndexDocumentFromDB struct {
+ Options bson.M `bson:",inline"`
+ Key bson.D `bson:"key"`
+}
+
+// dumpMetadata gets the metadata for a collection and writes it
+// in readable JSON format.
+func (dump *MongoDump) dumpMetadata(intent *intents.Intent) error {
+ var err error
+
+ nsID := fmt.Sprintf("%v.%v", intent.DB, intent.C)
+ meta := Metadata{
+ // We have to initialize Indexes to an empty slice, not nil, so that an empty
+ // array is marshalled into json instead of null. That is, {indexes:[]} is okay
+ // but {indexes:null} will cause assertions in our legacy C++ mongotools
+ Indexes: []interface{}{},
+ }
+
+ // The collection options were already gathered while building the list of intents.
+ // We convert them to JSON so that they can be written to the metadata json file as text.
+ if intent.Options != nil {
+ if meta.Options, err = bsonutil.ConvertBSONValueToJSON(*intent.Options); err != nil {
+ return fmt.Errorf("error converting collection options to JSON: %v", err)
+ }
+ } else {
+ meta.Options = nil
+ }
+
+ // Second, we read the collection's index information by either calling
+ // listIndexes (pre-2.7 systems) or querying system.indexes.
+ // We keep a running list of all the indexes
+ // for the current collection as we iterate over the cursor, and include
+ // that list as the "indexes" field of the metadata document.
+ log.Logvf(log.DebugHigh, "\treading indexes for `%v`", nsID)
+
+ session, err := dump.sessionProvider.GetSession()
+ if err != nil {
+ return err
+ }
+ defer session.Close()
+
+ // get the indexes
+ indexesIter, err := db.GetIndexes(session.DB(intent.DB).C(intent.C))
+ if err != nil {
+ return err
+ }
+ if indexesIter == nil {
+ log.Logvf(log.Always, "the collection %v appears to have been dropped after the dump started", intent.Namespace())
+ return nil
+ }
+
+ indexOpts := &bson.D{}
+ for indexesIter.Next(indexOpts) {
+ convertedIndex, err := bsonutil.ConvertBSONValueToJSON(*indexOpts)
+ if err != nil {
+ return fmt.Errorf("error converting index (%#v): %v", convertedIndex, err)
+ }
+ meta.Indexes = append(meta.Indexes, convertedIndex)
+ }
+
+ if err := indexesIter.Err(); err != nil {
+ return fmt.Errorf("error getting indexes for collection `%v`: %v", nsID, err)
+ }
+
+ // Finally, we send the results to the writer as JSON bytes
+ jsonBytes, err := json.Marshal(meta)
+ if err != nil {
+ return fmt.Errorf("error marshalling metadata json for collection `%v`: %v", nsID, err)
+ }
+
+ err = intent.MetadataFile.Open()
+ if err != nil {
+ return err
+ }
+ defer intent.MetadataFile.Close()
+ // make a buffered writer for nicer disk i/o
+ w := bufio.NewWriter(intent.MetadataFile)
+ _, err = w.Write(jsonBytes)
+ if err != nil {
+ return fmt.Errorf("error writing metadata for collection `%v` to disk: %v", nsID, err)
+ }
+ err = w.Flush()
+ if err != nil {
+ return fmt.Errorf("error writing metadata for collection `%v` to disk: %v", nsID, err)
+ }
+ return nil
+}