Project

General

Profile

1
package eu.dnetlib.data.mdstore.modular.mongodb;
2

    
3
import java.util.List;
4

    
5
import com.google.common.collect.Lists;
6
import com.google.common.primitives.Ints;
7
import com.mongodb.BasicDBObject;
8
import com.mongodb.BasicDBObjectBuilder;
9
import com.mongodb.DBObject;
10
import com.mongodb.client.AggregateIterable;
11
import com.mongodb.client.MongoCollection;
12
import com.mongodb.client.MongoDatabase;
13
import com.mongodb.client.model.CreateCollectionOptions;
14
import eu.dnetlib.data.mdstore.MDStoreServiceException;
15
import eu.dnetlib.data.mdstore.modular.MDStoreDescription;
16
import eu.dnetlib.data.mdstore.modular.RecordParserFactory;
17
import eu.dnetlib.data.mdstore.modular.connector.MDStore;
18
import eu.dnetlib.data.mdstore.modular.connector.MDStoreDBStatus;
19
import eu.dnetlib.data.mdstore.modular.connector.MDStoreDao;
20
import eu.dnetlib.data.mdstore.modular.connector.MDStoreTransactionManager;
21
import eu.dnetlib.data.mdstore.modular.mongodb.utils.MDStoreUtils;
22
import eu.dnetlib.miscutils.collections.FilteredCollection;
23
import eu.dnetlib.miscutils.collections.MappedCollection;
24
import eu.dnetlib.miscutils.datetime.DateUtils;
25
import eu.dnetlib.miscutils.functional.UnaryFunction;
26
import org.apache.commons.logging.Log;
27
import org.apache.commons.logging.LogFactory;
28
import org.bson.Document;
29
import org.springframework.beans.factory.annotation.Autowired;
30
import org.springframework.beans.factory.annotation.Required;
31

    
32
/**
33
 * Factory bean for MongoMDStore instances.
34
 *
35
 * @author marko
36
 */
37
public class MDStoreDaoImpl implements MDStoreDao {
38

    
39
	public static final String MD_ID = "mdId";
40
	public static final String FORMAT = "format";
41
	public static final String INTERPRETATION = "interpretation";
42
	public static final String LAYOUT = "layout";
43
	public static final String SIZE = "size";
44
	public static final String METADATA_NAME = "metadata";
45
	private static final Log log = LogFactory.getLog(MDStoreDaoImpl.class);
46
	private MongoDatabase db;
47

    
48
	private RecordParserFactory recordParserFactory;
49

    
50
	private boolean discardRecords = true;
51

    
52
	@Autowired
53
	private MDStoreTransactionManager transactionManager;
54

    
55
	/**
56
	 * {@inheritDoc}
57
	 */
58
	@Override
59
	public void createMDStore(final String mdId, final String format, final String interpretation, final String layout) throws MDStoreServiceException {
60
		transactionManager.createMDStore(mdId);
61
		final String internalId = transactionManager.getMDStoreCollection(mdId);
62

    
63
		if (!Lists.newArrayList(getDb().listCollectionNames()).contains(internalId)) {
64
			log.info(String.format("creating collection %s", internalId));
65
			getDb().createCollection(internalId, new CreateCollectionOptions());
66
		}
67
		final MongoCollection<DBObject> coll = getDb().getCollection(METADATA_NAME, DBObject.class);
68
		final BasicDBObject obj = new BasicDBObject();
69
		obj.put(MD_ID, mdId);
70
		obj.put(FORMAT, format);
71
		obj.put(INTERPRETATION, interpretation);
72
		obj.put(LAYOUT, layout);
73
		obj.put(SIZE, 0);
74
		coll.insertOne(obj);
75
	}
76

    
77
	/**
78
	 * {@inheritDoc}
79
	 */
80
	@Override
81
	public void deleteMDStore(final String mdId) throws MDStoreServiceException {
82
		final MongoCollection<DBObject> metadata = getDb().getCollection(METADATA_NAME, DBObject.class);
83
		if (metadata == null) throw new MDStoreServiceException("cannot find metadata collection");
84
		transactionManager.dropMDStore(mdId);
85
		metadata.deleteOne(new BasicDBObject(MD_ID, mdId));
86
		log.info("deleted mdId: " + mdId);
87
	}
88

    
89
	/**
90
	 * {@inheritDoc}
91
	 */
92
	@Override
93
	public MDStore getMDStore(final String mdId) throws MDStoreServiceException {
94
		final String internalId = transactionManager.getMDStoreCollection(mdId);
95
		return new MongoMDStore(mdId, getDb().getCollection(internalId, DBObject.class), getRecordParserFactory().newInstance(), isDiscardRecords(), getDb());
96
	}
97

    
98
	/**
99
	 * {@inheritDoc}
100
	 */
101
	@Override
102
	public MDStore readMDStore(final String mdId) throws MDStoreServiceException {
103
		final String internalId = transactionManager.readMdStore(mdId);
104
		return new MongoMDStore(mdId, getDb().getCollection(internalId, DBObject.class), getRecordParserFactory().newInstance(), isDiscardRecords(), getDb());
105
	}
106

    
107
	/**
108
	 * {@inheritDoc}
109
	 */
110
	@Override
111
	public MDStore startTransaction(final String mdId, final boolean refresh) throws MDStoreServiceException {
112
		final String transactionId = transactionManager.startTransaction(mdId, refresh);
113
		return new MongoMDStore(transactionId, getDb().getCollection(transactionId, DBObject.class), getRecordParserFactory().newInstance(), isDiscardRecords(),
114
				getDb());
115
	}
116

    
117
	/**
118
	 * {@inheritDoc}
119
	 */
120
	@Override
121
	public List<MDStoreDescription> listMDStores() {
122
		return MappedCollection.listMap(getDb().getCollection(METADATA_NAME, DBObject.class).find(), new UnaryFunction<MDStoreDescription, DBObject>() {
123

    
124
			@Override
125
			public MDStoreDescription evaluate(final DBObject input) {
126

    
127
				final String mdId = (String) input.get(MD_ID);
128
				log.debug("Getting info for " + mdId);
129
				final String format = (String) input.get(FORMAT);
130
				final String layout = (String) input.get(LAYOUT);
131
				final String interpretation = (String) input.get(INTERPRETATION);
132
				MongoMDStore currentMDStore = null;
133
				final MDStoreDescription description = new MDStoreDescription();
134
				try {
135
					currentMDStore = (MongoMDStore) getMDStore(mdId);
136
				} catch (final MDStoreServiceException e) {
137
					log.error("Error on retrieving mdstore for getting info mdId " + mdId);
138
				}
139

    
140
				int size = 0;
141
				if (input.containsField(SIZE)) {
142
					log.debug("Size retrieved from metadata for mdId :" + mdId);
143
					size = (Integer) input.get(SIZE);
144
				} else {
145
					if (currentMDStore != null) {
146
						log.debug("Size not Found in metadata for mdId :" + mdId + " calling getCount ");
147
						size = currentMDStore.getSize();
148
						input.put("size", size);
149
						getDb().getCollection(METADATA_NAME, DBObject.class).findOneAndReplace(new BasicDBObject(MD_ID, mdId), input);
150
					}
151
				}
152
				if (currentMDStore != null) {
153
					description.setIndexed(currentMDStore.isIndexed());
154
				}
155
				description.setId(mdId);
156
				description.setFormat(format);
157
				description.setLayout(layout);
158
				description.setInterpretation(interpretation);
159
				description.setSize(size);
160
				return description;
161
			}
162
		});
163
	}
164

    
165
	/**
166
	 * {@inheritDoc}
167
	 */
168
	@Override
169
	public List<String> listMDStores(final String format, final String layout, final String interpretation) {
170
		return MappedCollection.listMap(
171
				FilteredCollection.listFilter(getDb().getCollection(METADATA_NAME, DBObject.class).find(), MDStoreUtils.dboFilter(format, layout, interpretation)),
172
				MDStoreUtils.mdId());
173
	}
174

    
175
	/**
176
	 * {@inheritDoc}
177
	 */
178
	@Override
179
	public int getCachedSize(final String id) throws MDStoreServiceException {
180
		log.debug("retrieve cached size for mdstore: " + id);
181
		final DBObject desc = getDb().getCollection(METADATA_NAME, DBObject.class).find(new BasicDBObject(MD_ID, id)).first();
182
		if (!desc.containsField(SIZE)) {
183
			desc.put(SIZE, getMDStore(id).getSize());
184
		}
185

    
186
		final Object oSize = desc.get(SIZE);
187
		return (Integer) oSize;
188
	}
189

    
190
	/**
191
	 * {@inheritDoc}
192
	 */
193
	@Override
194
	public void refreshSizes() throws MDStoreServiceException {
195
		for (final MDStoreDescription mdStoreId : listMDStores()) {
196
			refreshSize(mdStoreId.getId());
197
		}
198
	}
199

    
200
	/**
201
	 * {@inheritDoc}
202
	 */
203
	@Override
204
	public int refreshSize(final String mdStoreId) throws MDStoreServiceException {
205
		final int size = (int) getDb().getCollection(transactionManager.getMDStoreCollection(mdStoreId)).count();
206
		final MongoCollection<DBObject> metadata = getDb().getCollection(METADATA_NAME, DBObject.class);
207
		metadata.updateOne(new BasicDBObject(MD_ID, mdStoreId), new BasicDBObject("$set", new BasicDBObject(SIZE, size)));
208
		return size;
209
	}
210

    
211
	@Override
212
	public int getSumOfSizes(final String format, final String layout, final String interpretation) throws MDStoreServiceException {
213
		final MongoCollection<DBObject> metadata = getDb().getCollection(METADATA_NAME, DBObject.class);
214
		BasicDBObject matchObj = (BasicDBObject) BasicDBObjectBuilder.start("$match",
215
				BasicDBObjectBuilder.start("format", format).add("layout", layout).add("interpretation", interpretation).get()).get();
216
		BasicDBObject groupObj = (BasicDBObject) BasicDBObjectBuilder.start("$group",
217
				BasicDBObjectBuilder.start("_id", "").add("total", new BasicDBObject("$sum", "$" + SIZE)).get()).get();
218
		BasicDBObject projectObj = new BasicDBObject("$project", new BasicDBObject("_id", 0).append("total", 1));
219
		List<BasicDBObject> pipeline = Lists.newArrayList(matchObj, groupObj, projectObj);
220
		AggregateIterable<DBObject> output = metadata.aggregate(pipeline, DBObject.class);
221
		DBObject result = output.first();
222
		if (result == null || !result.containsField("total")) {
223
			log.debug("No total found");
224
			return 0;
225
		} else return (Integer) result.get("total");
226
	}
227

    
228
	/**
229
	 * {@inheritDoc}
230
	 */
231
	@Override
232
	public void commit(final String transactionId, final String mdId) throws MDStoreServiceException {
233
		transactionManager.commit(transactionId, mdId, getMDStore(mdId));
234
	}
235

    
236
	/**
237
	 * Getter for property 'db'.
238
	 *
239
	 * @return Value for property 'db'.
240
	 */
241
	public MongoDatabase getDb() {
242
		return db;
243
	}
244

    
245
	/**
246
	 * Setter for property 'db'.
247
	 *
248
	 * @param db
249
	 *            Value to set for property 'db'.
250
	 */
251
	@Required
252
	public void setDb(final MongoDatabase db) {
253
		this.db = db;
254
	}
255

    
256
	/**
257
	 * Getter for property 'recordParser'.
258
	 *
259
	 * @return Value for property 'recordParser'.
260
	 */
261
	public RecordParserFactory getRecordParserFactory() {
262
		return recordParserFactory;
263
	}
264

    
265

    
266
	@Required
267
	public void setRecordParserFactory(final RecordParserFactory recordParserFactory) {
268
		this.recordParserFactory = recordParserFactory;
269
	}
270

    
271
	/**
272
	 * Getter for property 'discardRecords'.
273
	 *
274
	 * @return Value for property 'discardRecords'.
275
	 */
276
	public boolean isDiscardRecords() {
277
		return discardRecords;
278
	}
279

    
280
	/**
281
	 * Setter for property 'discardRecords'.
282
	 *
283
	 * @param discardRecords
284
	 *            Value to set for property 'discardRecords'.
285
	 */
286
	public void setDiscardRecords(final boolean discardRecords) {
287
		this.discardRecords = discardRecords;
288
	}
289

    
290
	@Override
291
	public MDStoreDBStatus getDBStatus() {
292
		final int handledDatastructures = Ints.saturatedCast(getDb().getCollection(METADATA_NAME).count());
293
		//final int usedDiskSpace = Ints.saturatedCast(getDb().getStats().getLong("storageSize") / (1024 * 1024)); // in MB
294
		//{ dbStats: 1, scale: 1 }
295
		BasicDBObject statsQuery = new BasicDBObject("dbStats", 1);
296
		statsQuery.put("scale", 1024 * 1024); //storageSize in MB
297
		final Document statsRes = getDb().runCommand(statsQuery);
298
		log.debug("DBStatus --  " + statsRes.toJson());
299
		int usedDiskSpace = 0;
300
		//trying to handle different versions of the mongo server: old version returns storage size as long, new version as double
301
		//TODO: simplify this when dev, beta, production are aligned with our local, latest, mongo version
302
		String usedDiskSpaceStr = statsRes.get("storageSize").toString();
303
		try {
304
			Long usedDiskSpaceLong = Long.parseLong(usedDiskSpaceStr);
305
			usedDiskSpace = Ints.saturatedCast(usedDiskSpaceLong);
306
		} catch (NumberFormatException nfe) {
307
			Double usedDiskSpaceDbl = Double.parseDouble(usedDiskSpaceStr);
308
			usedDiskSpace = usedDiskSpaceDbl.intValue();
309
		}
310
		final String date = DateUtils.now_ISO8601();
311
		return new MDStoreDBStatus(handledDatastructures, usedDiskSpace, date);
312
	}
313

    
314
	@Override
315
	public void startGarbage() throws MDStoreServiceException {
316
		this.transactionManager.garbage();
317
	}
318

    
319
	@Override
320
	public void invalidTransaction(final String transactionId, final String mdId) throws MDStoreServiceException {
321
		transactionManager.dropTransaction(mdId, transactionId);
322

    
323
	}
324

    
325
}
(1-1/5)