Switch to unified view

a/Allura/allura/model/index.py b/Allura/allura/model/index.py
...
...
14
from ming.utils import LazyProperty
14
from ming.utils import LazyProperty
15
from ming.orm import MappedClass, session
15
from ming.orm import MappedClass, session
16
from ming.orm import FieldProperty, ForeignIdProperty, RelationProperty
16
from ming.orm import FieldProperty, ForeignIdProperty, RelationProperty
17
17
18
from allura.lib import helpers as h
18
from allura.lib import helpers as h
19
from allura.lib.search import find_shortlinks, solarize
20
19
21
from .session import main_orm_session
20
from .session import main_orm_session
22
21
23
log = logging.getLogger(__name__)
22
log = logging.getLogger(__name__)
24
23
...
...
82
    _id = FieldProperty(S.ObjectId)
81
    _id = FieldProperty(S.ObjectId)
83
    ref_id = ForeignIdProperty(ArtifactReference)
82
    ref_id = ForeignIdProperty(ArtifactReference)
84
    project_id = ForeignIdProperty('Project')
83
    project_id = ForeignIdProperty('Project')
85
    app_config_id = ForeignIdProperty('AppConfig')
84
    app_config_id = ForeignIdProperty('AppConfig')
86
    link = FieldProperty(str)
85
    link = FieldProperty(str)
86
    url = FieldProperty(str)
87
87
88
    # Relation Properties
88
    # Relation Properties
89
    project = RelationProperty('Project')
89
    project = RelationProperty('Project')
90
    app_config = RelationProperty('AppConfig')
90
    app_config = RelationProperty('AppConfig')
91
    ref = RelationProperty('ArtifactReference')
91
    ref = RelationProperty('ArtifactReference')
...
...
117
        if result is None:
117
        if result is None:
118
            try:
118
            try:
119
                result = cls(
119
                result = cls(
120
                    ref_id = a.index_id(),
120
                    ref_id = a.index_id(),
121
                    project_id = a.app_config.project_id,
121
                    project_id = a.app_config.project_id,
122
                    app_config_id = a.app_config._id,
122
                    app_config_id = a.app_config._id)
123
                    link = a.shorthand_id())
124
                session(result).flush(result)
123
                session(result).flush(result)
125
            except pymongo.errors.DuplicateKeyError: # pragma no cover
124
            except pymongo.errors.DuplicateKeyError: # pragma no cover
126
                session(result).expunge(result)
125
                session(result).expunge(result)
127
                result = cls.query.get(ref_id=a.index_id())
126
                result = cls.query.get(ref_id=a.index_id())
127
        result.link = a.shorthand_id()
128
        result.url = a.url()
128
        return result
129
        return result
129
130
130
    @classmethod
131
    @classmethod
131
    def from_links(cls, *links):
132
    def from_links(cls, *links):
132
        '''Convert a sequence of shortlinks to the matching Shortlink objects'''
133
        '''Convert a sequence of shortlinks to the matching Shortlink objects'''
...
...
189
                app=None,
190
                app=None,
190
                artifact=parts[0])
191
                artifact=parts[0])
191
        else:
192
        else:
192
            return None
193
            return None
193
194
194
class IndexOp(MappedClass):
195
    '''Queued operations for offline indexing.
196
    '''
197
    class __mongometa__:
198
        session = main_orm_session
199
        name = 'index_op'
200
        indexes = [
201
           [ ('worker', ming.ASCENDING),
202
             ('ref_id', ming.ASCENDING),
203
             ('timestamp', ming.DESCENDING),
204
             ],
205
           ]
206
207
    _id = FieldProperty(S.ObjectId)
208
    op = FieldProperty(S.OneOf('add', 'del'))
209
    worker = FieldProperty(str, if_missing=None)
210
    ref_id = ForeignIdProperty('ArtifactReference')
211
    timestamp = FieldProperty(datetime, if_missing=datetime.utcnow)
212
213
    ref = RelationProperty('ArtifactReference')
214
215
    def __repr__(self):
216
        return '<%s %s (%s) @%s>' % (
217
            self.op, self.ref_id, self.worker, self.timestamp.isoformat())
218
219
    @classmethod
220
    def add_op(cls, artifact):
221
        return cls(op='add', ref_id=artifact.index_id())
222
223
    @classmethod
224
    def del_op(cls, artifact):
225
        return cls(op='del', ref_id=artifact.index_id())
226
227
    @classmethod
228
    def lock_ops(cls, worker):
229
        '''Lock all the outstanding indexops to the given worker'''
230
        cls.query.update(
231
            dict(worker=None),
232
            {'$set': dict(worker=worker)},
233
            multi=True)
234
235
    @classmethod
236
    def remove_ops(cls, worker):
237
        '''Remove all the ops locked by the given worker'''
238
        cls.query.remove(dict(worker=worker))
239
240
    @classmethod
241
    def unlock_ops(cls, worker):
242
        '''Unlock all the outstanding indexops to the given worker
243
244
        Generally only used if the worker dies.
245
        '''
246
        cls.query.update(
247
            dict(worker=worker),
248
            {'$set': dict(worker=None)},
249
            multi=True)
250
251
    @classmethod
252
    def find_ops(cls, worker):
253
        '''Return the most relevant ops locked by worker
254
255
        This method will only return the most recent op for a particular
256
        artifact (which is what you actually want).
257
        '''
258
        q = (cls
259
             .query
260
             .find(dict(worker=worker))
261
             .sort('ref_id')
262
             .sort('timestamp', ming.DESCENDING))
263
        for ref_id, ops in groupby(q, key=lambda o: o.ref_id):
264
            yield ops.next()
265
266
    def __call__(self):
267
        from allura.model.artifact import Snapshot
268
        try:
269
            if self.op == 'add':
270
                artifact = self.ref.artifact
271
                Shortlink.from_artifact(artifact)
272
                s = solarize(artifact)
273
                if s is not None:
274
                    g.solr.add([s])
275
                    if not isinstance(artifact, Snapshot):
276
                        self.ref.references = [
277
                            link.ref_id for link in find_shortlinks(s['text']) ]
278
            else:
279
                g.solr.delete(id=self.ref_id)
280
                ArtifactReference.query.remove(dict(_id=self.ref_id))
281
                Shortlink.query.remove(dict(ref_id=self.ref_id))
282
        except:
283
            log.exception('Error with %r', self)
284
            self.worker = 'ERROR'
285
            session(self).flush(self)