summaryrefslogtreecommitdiff
path: root/db/repl.h
blob: e4c95bfa21e29acfe2958a4f16fa9c500d70043a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// repl.h - replication

/**
*    Copyright (C) 2008 10gen Inc.
*  
*    This program is free software: you can redistribute it and/or  modify
*    it under the terms of the GNU Affero General Public License, version 3,
*    as published by the Free Software Foundation.
*  
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU Affero General Public License for more details.
*  
*    You should have received a copy of the GNU Affero General Public License
*    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/* replication data overview

   at the slave: 
     local.sources { host: ..., source: ..., syncedTo: ..., dbs: { ... } }

   at the master:
     local.oplog.$<source>
     local.oplog.$main is the default
*/

#pragma once

class DBClientConnection;
class DBClientCursor;
extern bool slave;
extern bool master;

bool cloneFrom(const char *masterHost, string& errmsg);

#pragma pack(push,4)
class OpTime { 
	unsigned i;
	unsigned secs;
public:
	OpTime(unsigned long long date) { 
		reinterpret_cast<unsigned long long&>(*this) = date;
	}
	OpTime(unsigned a, unsigned b) { secs = a; i = b; }
	OpTime() { secs = 0; i = 0; }
	static OpTime now();

	  /* We store OpTime's in the database as Javascript Date datatype -- we needed some sort of 
	     64 bit "container" for these values.  While these are not really "Dates", that seems a 
		 better choice for now than say, Number, which is floating point.  Note the BinData type 
		 is perhaps the cleanest choice, lacking a true unsigned64 datatype, but BinData has a 
		 couple bytes of overhead.
	  */
	  unsigned long long asDate() const { return *((unsigned long long *) &i); } 
//	  unsigned long long& asDate() { return *((unsigned long long *) &i); } 

	  bool isNull() { return secs == 0; }
	  string toString() const { 
		  stringstream ss;
		  ss << hex << secs << ':' << i;
		  return ss.str();
	  }
	  bool operator==(const OpTime& r) const { 
		  return i == r.i && secs == r.secs;
	  }
	  bool operator!=(const OpTime& r) const { return !(*this == r); }
	  bool operator<(const OpTime& r) const { 
		  if( secs != r.secs ) 
			  return secs < r.secs;
		  return i < r.i;
	  }
};
#pragma pack(pop)

/* A replication exception */
struct SyncException { 
};

/* A Source is a source from which we can pull (replicate) data.
   stored in collection local.sources.

   Can be a group of things to replicate for several databases.

      { host: ..., source: ..., syncedTo: ..., dbs: { ... } }
*/
class Source {
	bool resync(string db);
	void pullOpLog();
	void applyOperation(JSObj& op);

	auto_ptr<DBClientConnection> conn;
	auto_ptr<DBClientCursor> cursor;
public:
	string hostName;    // ip addr or hostname
	string sourceName;  // a logical source name.

	/* the last time point we have already synced up to. */
	OpTime syncedTo;

	/* list of databases that we have synced. 
	   we need this so that if we encounter a new one, we know 
	   to go fetch the old data.
	*/
	set<string> dbs;

	static void loadAll(vector<Source*>&);
	static void cleanup(vector<Source*>&);
	Source(JSObj);
	bool sync();
	void save(); // write ourself to local.sources
	void resetConnection() { conn = auto_ptr<DBClientConnection>(0); }

	// make a jsobj from our member fields of the form 
	//   { host: ..., source: ..., syncedTo: ... }
	JSObj jsobj(); 
	
	bool operator==(const Source&r) const { 
		return hostName == r.hostName && sourceName == r.sourceName; 
	}
};

/* Write operation to the log (local.oplog.$main)
   "i" insert
   "u" update
   "d" delete
   "c" db cmd
*/
void _logOp(const char *opstr, const char *ns, JSObj& obj, JSObj *patt, bool *b);
inline void logOp(const char *opstr, const char *ns, JSObj& obj, JSObj *patt = 0, bool *b = 0) {
	if( master )
		_logOp(opstr, ns, obj, patt, b);
}