summaryrefslogtreecommitdiff
path: root/designs/syncs.json
blob: f9aa90d223fa046794da63b82523bb200f811348 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
   "_id": "_design/syncs", 
   "updates": {
      "put": "function(doc, req){\n    if (!doc) {\n        doc = {}\n        doc['_id'] = 'u1db_sync_log';\n        doc['syncs'] = [];\n    }\n    body = JSON.parse(req.body);\n    // remove outdated info\n    doc['syncs'] = doc['syncs'].filter(\n        function (entry) {\n            return entry[0] != body['other_replica_uid'];\n        }\n    );\n    // store u1db rev\n    doc['syncs'].push([\n        body['other_replica_uid'],\n        body['other_generation'],\n        body['other_transaction_id']\n    ]);\n    return [doc, 'ok'];\n}\n\n", 
      "state": "/**\n * This update handler stores information about ongoing synchronization\n * attempts from distinct source replicas.\n *\n * Normally, u1db synchronization occurs during one POST request. In order to\n * split that into many serial POST requests, we store the state of each sync\n * in the server, using a document with id 'u1db_sync_state'.  To identify\n * each sync attempt, we use a sync_id sent by the client. If we ever receive\n * a new sync_id, we trash current data for that source replica and start\n * over.\n *\n * We expect the following in the document body:\n *\n * {\n *     'source_replica_uid': '<source_replica_uid>',\n *     'sync_id': '<sync_id>',\n *     'seen_ids': [['<doc_id>', <at_gen>], ...],     // optional\n *     'changes_to_return': [                         // optional\n *         'gen': <gen>,\n *         'trans_id': '<trans_id>',\n *         'changes_to_return': [[<doc_id>', <gen>, '<trans_id>'], ...]\n *     ],\n * }\n *\n * The format of the final document stored on server is:\n *\n * {\n *     '_id': '<str>',\n *     '_rev' '<str>',\n *     'ongoing_syncs': {\n *         '<source_replica_uid>': {\n *             'sync_id': '<sync_id>',\n *             'seen_ids': [['<doc_id>', <at_gen>[, ...],\n *             'changes_to_return': {\n *                  'gen': <gen>,\n *                  'trans_id': '<trans_id>',\n *                  'changes_to_return': [\n *                          ['<doc_id>', <gen>, '<trans_id>'],\n *                          ...,\n *                  ],\n *             },\n *         },\n *         ... // info about other source replicas here\n *     }\n * }\n */\nfunction(doc, req) {\n\n    // prevent updates to alien documents\n    if (doc != null && doc['_id'] != 'u1db_sync_state')\n        return [null, 'invalid data'];\n\n    // create the document if it doesn't exist\n    if (!doc)\n        doc = {\n            '_id': 'u1db_sync_state',\n            'ongoing_syncs': {},\n        };\n\n    // parse and validate incoming data\n    var body = JSON.parse(req.body);\n    if (body['source_replica_uid'] == null)\n        return [null, 'invalid data'];\n    var source_replica_uid = body['source_replica_uid'];\n\n    if (body['sync_id'] == null)\n        return [null, 'invalid data'];\n    var sync_id = body['sync_id'];\n\n    // trash outdated sync data for that replica if that exists\n    if (doc['ongoing_syncs'][source_replica_uid] != null &&\n            doc['ongoing_syncs'][source_replica_uid]['sync_id'] != sync_id)\n        delete doc['ongoing_syncs'][source_replica_uid];\n\n    // create an entry for that source replica\n    if (doc['ongoing_syncs'][source_replica_uid] == null)\n        doc['ongoing_syncs'][source_replica_uid] = {\n            'sync_id': sync_id,\n            'seen_ids': {},\n            'changes_to_return': null,\n        };\n\n    // incoming meta-data values should be exclusive, so we count how many\n    // arrived and deny to accomplish the transaction if the count is high.\n    var incoming_values = 0;\n    var info = doc['ongoing_syncs'][source_replica_uid]\n\n    // add incoming seen id\n    if ('seen_id' in body) {\n        info['seen_ids'][body['seen_id'][0]] = body['seen_id'][1];\n        incoming_values += 1;\n    }\n\n    // add incoming changes_to_return\n    if ('changes_to_return' in body) {\n        info['changes_to_return'] = body['changes_to_return'];\n        incoming_values += 1;\n    }\n\n    if (incoming_values != 1)\n        return [null, 'invalid data'];\n\n    return [doc, 'ok'];\n}\n\n"
   }, 
   "views": {
      "state": {
         "map": "function(doc) {\n  if (doc['_id'] == 'u1db_sync_state' && doc['ongoing_syncs'] != null)\n    for (var source_replica_uid in doc['ongoing_syncs']) {\n      var changes = doc['ongoing_syncs'][source_replica_uid]['changes_to_return'];\n      var sync_id = doc['ongoing_syncs'][source_replica_uid]['sync_id'];\n      if (changes == null)\n        emit([source_replica_uid, sync_id], null);\n      else\n        emit(\n          [source_replica_uid, sync_id],\n          {\n            'gen': changes['gen'],\n            'trans_id': changes['trans_id'],\n            'number_of_changes': changes['changes_to_return'].length\n          });\n    }\n}\n"
      }, 
      "changes_to_return": {
         "map": "function(doc) {\n  if (doc['_id'] == 'u1db_sync_state' && doc['ongoing_syncs'] != null)\n    for (var source_replica_uid in doc['ongoing_syncs']) {\n      var changes = doc['ongoing_syncs'][source_replica_uid]['changes_to_return'];\n      var sync_id = doc['ongoing_syncs'][source_replica_uid]['sync_id'];\n      if (changes == null)\n        emit([source_replica_uid, sync_id, 0], null);\n      else if (changes.length == 0)\n        emit([source_replica_uid, sync_id, 0], []);\n      else\n        for (var i = 0; i < changes['changes_to_return'].length; i++)\n          emit(\n            [source_replica_uid, sync_id, i],\n            {\n              'gen': changes['gen'],\n              'trans_id': changes['trans_id'],\n              'next_change_to_return': changes['changes_to_return'][i],\n            });\n    }\n}\n"
      }, 
      "log": {
         "map": "function(doc) {\n    if (doc._id == 'u1db_sync_log') {\n        if (doc.syncs)\n            doc.syncs.forEach(function (entry) {\n                emit(entry[0],\n                    {\n                        'known_generation': entry[1],\n                        'known_transaction_id': entry[2]\n                    });\n            });\n    }\n}\n"
      }, 
      "seen_ids": {
         "map": "function(doc) {\n  if (doc['_id'] == 'u1db_sync_state' && doc['ongoing_syncs'] != null)\n    for (var source_replica_uid in doc['ongoing_syncs']) {\n      var sync_id = doc['ongoing_syncs'][source_replica_uid]['sync_id'];\n      emit(\n        [source_replica_uid, sync_id],\n        {\n          'seen_ids': doc['ongoing_syncs'][source_replica_uid]['seen_ids'],\n        });\n    }\n}\n"
      }
   }
}