Mercurial > hg > orthanc
comparison OrthancServer/ServerIndex.cpp @ 759:8cfc6119a5bd dicom-rt
integration mainline -> dicom-rt
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 16 Apr 2014 16:04:55 +0200 |
parents | ec69658b031b |
children | 67e6400fca03 401a9633e492 |
comparison
equal
deleted
inserted
replaced
605:b82292ba2083 | 759:8cfc6119a5bd |
---|---|
1 /** | 1 /** |
2 * Orthanc - A Lightweight, RESTful DICOM Store | 2 * Orthanc - A Lightweight, RESTful DICOM Store |
3 * Copyright (C) 2012-2013 Medical Physics Department, CHU of Liege, | 3 * Copyright (C) 2012-2014 Medical Physics Department, CHU of Liege, |
4 * Belgium | 4 * Belgium |
5 * | 5 * |
6 * This program is free software: you can redistribute it and/or | 6 * This program is free software: you can redistribute it and/or |
7 * modify it under the terms of the GNU General Public License as | 7 * modify it under the terms of the GNU General Public License as |
8 * published by the Free Software Foundation, either version 3 of the | 8 * published by the Free Software Foundation, either version 3 of the |
89 | 89 |
90 void CommitFilesToRemove() | 90 void CommitFilesToRemove() |
91 { | 91 { |
92 for (std::list<std::string>::iterator | 92 for (std::list<std::string>::iterator |
93 it = pendingFilesToRemove_.begin(); | 93 it = pendingFilesToRemove_.begin(); |
94 it != pendingFilesToRemove_.end(); it++) | 94 it != pendingFilesToRemove_.end(); ++it) |
95 { | 95 { |
96 context_.RemoveFile(*it); | 96 context_.RemoveFile(*it); |
97 } | 97 } |
98 } | 98 } |
99 | 99 |
253 { | 253 { |
254 unsigned int sleep; | 254 unsigned int sleep; |
255 | 255 |
256 try | 256 try |
257 { | 257 { |
258 boost::mutex::scoped_lock lock(that->mutex_); | |
258 std::string sleepString = that->db_->GetGlobalProperty(GlobalProperty_FlushSleep); | 259 std::string sleepString = that->db_->GetGlobalProperty(GlobalProperty_FlushSleep); |
259 sleep = boost::lexical_cast<unsigned int>(sleepString); | 260 sleep = boost::lexical_cast<unsigned int>(sleepString); |
260 } | 261 } |
261 catch (boost::bad_lexical_cast&) | 262 catch (boost::bad_lexical_cast&) |
262 { | 263 { |
288 | 289 |
289 static void ComputeExpectedNumberOfInstances(DatabaseWrapper& db, | 290 static void ComputeExpectedNumberOfInstances(DatabaseWrapper& db, |
290 int64_t series, | 291 int64_t series, |
291 const DicomMap& dicomSummary) | 292 const DicomMap& dicomSummary) |
292 { | 293 { |
293 const DicomValue* value; | 294 try |
294 const DicomValue* value2; | 295 { |
296 const DicomValue* value; | |
297 const DicomValue* value2; | |
295 | 298 |
296 try | |
297 { | |
298 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGES_IN_ACQUISITION)) != NULL && | 299 if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGES_IN_ACQUISITION)) != NULL && |
299 (value2 = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS)) != NULL) | 300 (value2 = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS)) != NULL) |
300 { | 301 { |
301 // Patch for series with temporal positions thanks to Will Ryder | 302 // Patch for series with temporal positions thanks to Will Ryder |
302 int64_t imagesInAcquisition = boost::lexical_cast<int64_t>(value->AsString()); | 303 int64_t imagesInAcquisition = boost::lexical_cast<int64_t>(value->AsString()); |
405 } | 406 } |
406 | 407 |
407 // Ensure there is enough room in the storage for the new instance | 408 // Ensure there is enough room in the storage for the new instance |
408 uint64_t instanceSize = 0; | 409 uint64_t instanceSize = 0; |
409 for (Attachments::const_iterator it = attachments.begin(); | 410 for (Attachments::const_iterator it = attachments.begin(); |
410 it != attachments.end(); it++) | 411 it != attachments.end(); ++it) |
411 { | 412 { |
412 instanceSize += it->GetCompressedSize(); | 413 instanceSize += it->GetCompressedSize(); |
413 } | 414 } |
414 | 415 |
415 Recycle(instanceSize, hasher.HashPatient()); | 416 Recycle(instanceSize, hasher.HashPatient()); |
510 assert(series != -1); | 511 assert(series != -1); |
511 assert(instance != -1); | 512 assert(instance != -1); |
512 | 513 |
513 // Attach the files to the newly created instance | 514 // Attach the files to the newly created instance |
514 for (Attachments::const_iterator it = attachments.begin(); | 515 for (Attachments::const_iterator it = attachments.begin(); |
515 it != attachments.end(); it++) | 516 it != attachments.end(); ++it) |
516 { | 517 { |
517 db_->AddAttachment(instance, *it); | 518 db_->AddAttachment(instance, *it); |
518 } | 519 } |
519 | 520 |
520 // Attach the metadata | 521 // Attach the metadata |
591 | 592 |
592 size_t expected; | 593 size_t expected; |
593 try | 594 try |
594 { | 595 { |
595 expected = boost::lexical_cast<size_t>(s); | 596 expected = boost::lexical_cast<size_t>(s); |
596 if (expected < 0) | |
597 { | |
598 return SeriesStatus_Unknown; | |
599 } | |
600 } | 597 } |
601 catch (boost::bad_lexical_cast&) | 598 catch (boost::bad_lexical_cast&) |
602 { | 599 { |
603 return SeriesStatus_Unknown; | 600 return SeriesStatus_Unknown; |
604 } | 601 } |
607 std::list<int64_t> children; | 604 std::list<int64_t> children; |
608 db_->GetChildrenInternalId(children, id); | 605 db_->GetChildrenInternalId(children, id); |
609 | 606 |
610 std::set<size_t> instances; | 607 std::set<size_t> instances; |
611 for (std::list<int64_t>::const_iterator | 608 for (std::list<int64_t>::const_iterator |
612 it = children.begin(); it != children.end(); it++) | 609 it = children.begin(); it != children.end(); ++it) |
613 { | 610 { |
614 // Get the index of this instance in the series | 611 // Get the index of this instance in the series |
615 s = db_->GetMetadata(*it, MetadataType_Instance_IndexInSeries); | 612 s = db_->GetMetadata(*it, MetadataType_Instance_IndexInSeries); |
616 size_t index; | 613 size_t index; |
617 try | 614 try |
621 catch (boost::bad_lexical_cast&) | 618 catch (boost::bad_lexical_cast&) |
622 { | 619 { |
623 return SeriesStatus_Unknown; | 620 return SeriesStatus_Unknown; |
624 } | 621 } |
625 | 622 |
626 if (index <= 0 || index > expected) | 623 if (!(index > 0 && index <= expected)) |
627 { | 624 { |
628 // Out-of-range instance index | 625 // Out-of-range instance index |
629 return SeriesStatus_Inconsistent; | 626 return SeriesStatus_Inconsistent; |
630 } | 627 } |
631 | 628 |
713 if (type != ResourceType_Instance) | 710 if (type != ResourceType_Instance) |
714 { | 711 { |
715 Json::Value c = Json::arrayValue; | 712 Json::Value c = Json::arrayValue; |
716 | 713 |
717 for (std::list<std::string>::const_iterator | 714 for (std::list<std::string>::const_iterator |
718 it = children.begin(); it != children.end(); it++) | 715 it = children.begin(); it != children.end(); ++it) |
719 { | 716 { |
720 c.append(*it); | 717 c.append(*it); |
721 } | 718 } |
722 | 719 |
723 switch (type) | 720 switch (type) |
821 { | 818 { |
822 boost::mutex::scoped_lock lock(mutex_); | 819 boost::mutex::scoped_lock lock(mutex_); |
823 | 820 |
824 int64_t id; | 821 int64_t id; |
825 ResourceType type; | 822 ResourceType type; |
826 if (!db_->LookupResource(instanceUuid, id, type) || | 823 if (!db_->LookupResource(instanceUuid, id, type)) |
827 type != ResourceType_Instance) | |
828 { | 824 { |
829 throw OrthancException(ErrorCode_InternalError); | 825 throw OrthancException(ErrorCode_InternalError); |
830 } | 826 } |
831 | 827 |
832 if (db_->LookupAttachment(attachment, id, contentType)) | 828 if (db_->LookupAttachment(attachment, id, contentType)) |
1110 else | 1106 else |
1111 LOG(INFO) << "Patient " << publicId << " has been unprotected"; | 1107 LOG(INFO) << "Patient " << publicId << " has been unprotected"; |
1112 } | 1108 } |
1113 | 1109 |
1114 | 1110 |
1111 void ServerIndex::GetChildren(std::list<std::string>& result, | |
1112 const std::string& publicId) | |
1113 { | |
1114 result.clear(); | |
1115 | |
1116 boost::mutex::scoped_lock lock(mutex_); | |
1117 | |
1118 ResourceType type; | |
1119 int64_t resource; | |
1120 if (!db_->LookupResource(publicId, resource, type)) | |
1121 { | |
1122 throw OrthancException(ErrorCode_UnknownResource); | |
1123 } | |
1124 | |
1125 if (type == ResourceType_Instance) | |
1126 { | |
1127 // An instance cannot have a child | |
1128 throw OrthancException(ErrorCode_BadParameterType); | |
1129 } | |
1130 | |
1131 std::list<int64_t> tmp; | |
1132 db_->GetChildrenInternalId(tmp, resource); | |
1133 | |
1134 for (std::list<int64_t>::const_iterator | |
1135 it = tmp.begin(); it != tmp.end(); ++it) | |
1136 { | |
1137 result.push_back(db_->GetPublicId(*it)); | |
1138 } | |
1139 } | |
1140 | |
1141 | |
1115 void ServerIndex::GetChildInstances(std::list<std::string>& result, | 1142 void ServerIndex::GetChildInstances(std::list<std::string>& result, |
1116 const std::string& publicId) | 1143 const std::string& publicId) |
1117 { | 1144 { |
1118 result.clear(); | 1145 result.clear(); |
1119 | 1146 |
1151 else | 1178 else |
1152 { | 1179 { |
1153 // Tag all the children of this resource as to be explored | 1180 // Tag all the children of this resource as to be explored |
1154 db_->GetChildrenInternalId(tmp, resource); | 1181 db_->GetChildrenInternalId(tmp, resource); |
1155 for (std::list<int64_t>::const_iterator | 1182 for (std::list<int64_t>::const_iterator |
1156 it = tmp.begin(); it != tmp.end(); it++) | 1183 it = tmp.begin(); it != tmp.end(); ++it) |
1157 { | 1184 { |
1158 toExplore.push(*it); | 1185 toExplore.push(*it); |
1159 } | 1186 } |
1160 } | 1187 } |
1161 } | 1188 } |
1210 | 1237 |
1211 return db_->LookupMetadata(target, id, type); | 1238 return db_->LookupMetadata(target, id, type); |
1212 } | 1239 } |
1213 | 1240 |
1214 | 1241 |
1215 bool ServerIndex::ListAvailableMetadata(std::list<MetadataType>& target, | 1242 void ServerIndex::ListAvailableMetadata(std::list<MetadataType>& target, |
1216 const std::string& publicId) | 1243 const std::string& publicId) |
1217 { | 1244 { |
1218 boost::mutex::scoped_lock lock(mutex_); | 1245 boost::mutex::scoped_lock lock(mutex_); |
1219 | 1246 |
1220 ResourceType rtype; | 1247 ResourceType rtype; |
1222 if (!db_->LookupResource(publicId, id, rtype)) | 1249 if (!db_->LookupResource(publicId, id, rtype)) |
1223 { | 1250 { |
1224 throw OrthancException(ErrorCode_UnknownResource); | 1251 throw OrthancException(ErrorCode_UnknownResource); |
1225 } | 1252 } |
1226 | 1253 |
1227 return db_->ListAvailableMetadata(target, id); | 1254 db_->ListAvailableMetadata(target, id); |
1255 } | |
1256 | |
1257 | |
1258 void ServerIndex::ListAvailableAttachments(std::list<FileContentType>& target, | |
1259 const std::string& publicId, | |
1260 ResourceType expectedType) | |
1261 { | |
1262 boost::mutex::scoped_lock lock(mutex_); | |
1263 | |
1264 ResourceType type; | |
1265 int64_t id; | |
1266 if (!db_->LookupResource(publicId, id, type) || | |
1267 expectedType != type) | |
1268 { | |
1269 throw OrthancException(ErrorCode_UnknownResource); | |
1270 } | |
1271 | |
1272 db_->ListAvailableAttachments(target, id); | |
1228 } | 1273 } |
1229 | 1274 |
1230 | 1275 |
1231 bool ServerIndex::LookupParent(std::string& target, | 1276 bool ServerIndex::LookupParent(std::string& target, |
1232 const std::string& publicId) | 1277 const std::string& publicId) |
1299 boost::mutex::scoped_lock lock(mutex_); | 1344 boost::mutex::scoped_lock lock(mutex_); |
1300 db_->ClearTable("ExportedResources"); | 1345 db_->ClearTable("ExportedResources"); |
1301 } | 1346 } |
1302 | 1347 |
1303 | 1348 |
1304 void ServerIndex::GetStatistics(Json::Value& target, | 1349 void ServerIndex::GetStatisticsInternal(/* out */ uint64_t& compressedSize, |
1305 const std::string& publicId) | 1350 /* out */ uint64_t& uncompressedSize, |
1306 { | 1351 /* out */ unsigned int& countStudies, |
1307 boost::mutex::scoped_lock lock(mutex_); | 1352 /* out */ unsigned int& countSeries, |
1308 | 1353 /* out */ unsigned int& countInstances, |
1309 ResourceType type; | 1354 /* in */ int64_t id, |
1310 int64_t top; | 1355 /* in */ ResourceType type) |
1311 if (!db_->LookupResource(publicId, top, type)) | 1356 { |
1312 { | |
1313 throw OrthancException(ErrorCode_UnknownResource); | |
1314 } | |
1315 | |
1316 std::stack<int64_t> toExplore; | 1357 std::stack<int64_t> toExplore; |
1317 toExplore.push(top); | 1358 toExplore.push(id); |
1318 | 1359 |
1319 int countInstances = 0; | 1360 countInstances = 0; |
1320 int countSeries = 0; | 1361 countSeries = 0; |
1321 int countStudies = 0; | 1362 countStudies = 0; |
1322 uint64_t compressedSize = 0; | 1363 compressedSize = 0; |
1323 uint64_t uncompressedSize = 0; | 1364 uncompressedSize = 0; |
1324 | 1365 |
1325 while (!toExplore.empty()) | 1366 while (!toExplore.empty()) |
1326 { | 1367 { |
1327 // Get the internal ID of the current resource | 1368 // Get the internal ID of the current resource |
1328 int64_t resource = toExplore.top(); | 1369 int64_t resource = toExplore.top(); |
1329 toExplore.pop(); | 1370 toExplore.pop(); |
1330 | 1371 |
1331 ResourceType thisType = db_->GetResourceType(resource); | 1372 ResourceType thisType = db_->GetResourceType(resource); |
1332 | 1373 |
1374 std::list<FileContentType> f; | |
1375 db_->ListAvailableAttachments(f, resource); | |
1376 | |
1377 for (std::list<FileContentType>::const_iterator | |
1378 it = f.begin(); it != f.end(); ++it) | |
1379 { | |
1380 FileInfo attachment; | |
1381 if (db_->LookupAttachment(attachment, resource, *it)) | |
1382 { | |
1383 compressedSize += attachment.GetCompressedSize(); | |
1384 uncompressedSize += attachment.GetUncompressedSize(); | |
1385 } | |
1386 } | |
1387 | |
1333 if (thisType == ResourceType_Instance) | 1388 if (thisType == ResourceType_Instance) |
1334 { | 1389 { |
1335 std::list<FileContentType> f; | |
1336 db_->ListAvailableAttachments(f, resource); | |
1337 | |
1338 for (std::list<FileContentType>::const_iterator | |
1339 it = f.begin(); it != f.end(); it++) | |
1340 { | |
1341 FileInfo attachment; | |
1342 if (db_->LookupAttachment(attachment, resource, *it)) | |
1343 { | |
1344 compressedSize += attachment.GetCompressedSize(); | |
1345 uncompressedSize += attachment.GetUncompressedSize(); | |
1346 } | |
1347 } | |
1348 | |
1349 countInstances++; | 1390 countInstances++; |
1350 } | 1391 } |
1351 else | 1392 else |
1352 { | 1393 { |
1353 switch (thisType) | 1394 switch (thisType) |
1366 | 1407 |
1367 // Tag all the children of this resource as to be explored | 1408 // Tag all the children of this resource as to be explored |
1368 std::list<int64_t> tmp; | 1409 std::list<int64_t> tmp; |
1369 db_->GetChildrenInternalId(tmp, resource); | 1410 db_->GetChildrenInternalId(tmp, resource); |
1370 for (std::list<int64_t>::const_iterator | 1411 for (std::list<int64_t>::const_iterator |
1371 it = tmp.begin(); it != tmp.end(); it++) | 1412 it = tmp.begin(); it != tmp.end(); ++it) |
1372 { | 1413 { |
1373 toExplore.push(*it); | 1414 toExplore.push(*it); |
1374 } | 1415 } |
1375 } | 1416 } |
1376 } | 1417 } |
1418 | |
1419 if (countStudies == 0) | |
1420 { | |
1421 countStudies = 1; | |
1422 } | |
1423 | |
1424 if (countSeries == 0) | |
1425 { | |
1426 countSeries = 1; | |
1427 } | |
1428 } | |
1429 | |
1430 | |
1431 | |
1432 void ServerIndex::GetStatistics(Json::Value& target, | |
1433 const std::string& publicId) | |
1434 { | |
1435 boost::mutex::scoped_lock lock(mutex_); | |
1436 | |
1437 ResourceType type; | |
1438 int64_t top; | |
1439 if (!db_->LookupResource(publicId, top, type)) | |
1440 { | |
1441 throw OrthancException(ErrorCode_UnknownResource); | |
1442 } | |
1443 | |
1444 uint64_t uncompressedSize; | |
1445 uint64_t compressedSize; | |
1446 unsigned int countStudies; | |
1447 unsigned int countSeries; | |
1448 unsigned int countInstances; | |
1449 GetStatisticsInternal(compressedSize, uncompressedSize, countStudies, | |
1450 countSeries, countInstances, top, type); | |
1377 | 1451 |
1378 target = Json::objectValue; | 1452 target = Json::objectValue; |
1379 target["DiskSize"] = boost::lexical_cast<std::string>(compressedSize); | 1453 target["DiskSize"] = boost::lexical_cast<std::string>(compressedSize); |
1380 target["DiskSizeMB"] = boost::lexical_cast<unsigned int>(compressedSize / MEGA_BYTES); | 1454 target["DiskSizeMB"] = boost::lexical_cast<unsigned int>(compressedSize / MEGA_BYTES); |
1381 target["UncompressedSize"] = boost::lexical_cast<std::string>(uncompressedSize); | 1455 target["UncompressedSize"] = boost::lexical_cast<std::string>(uncompressedSize); |
1395 | 1469 |
1396 case ResourceType_Instance: | 1470 case ResourceType_Instance: |
1397 default: | 1471 default: |
1398 break; | 1472 break; |
1399 } | 1473 } |
1474 } | |
1475 | |
1476 | |
1477 void ServerIndex::GetStatistics(/* out */ uint64_t& compressedSize, | |
1478 /* out */ uint64_t& uncompressedSize, | |
1479 /* out */ unsigned int& countStudies, | |
1480 /* out */ unsigned int& countSeries, | |
1481 /* out */ unsigned int& countInstances, | |
1482 const std::string& publicId) | |
1483 { | |
1484 boost::mutex::scoped_lock lock(mutex_); | |
1485 | |
1486 ResourceType type; | |
1487 int64_t top; | |
1488 if (!db_->LookupResource(publicId, top, type)) | |
1489 { | |
1490 throw OrthancException(ErrorCode_UnknownResource); | |
1491 } | |
1492 | |
1493 GetStatisticsInternal(compressedSize, uncompressedSize, countStudies, | |
1494 countSeries, countInstances, top, type); | |
1400 } | 1495 } |
1401 | 1496 |
1402 | 1497 |
1403 void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that) | 1498 void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that) |
1404 { | 1499 { |
1471 | 1566 |
1472 | 1567 |
1473 | 1568 |
1474 void ServerIndex::LookupTagValue(std::list<std::string>& result, | 1569 void ServerIndex::LookupTagValue(std::list<std::string>& result, |
1475 DicomTag tag, | 1570 DicomTag tag, |
1476 const std::string& value) | 1571 const std::string& value, |
1572 ResourceType type) | |
1477 { | 1573 { |
1478 result.clear(); | 1574 result.clear(); |
1479 | 1575 |
1480 boost::mutex::scoped_lock lock(mutex_); | 1576 boost::mutex::scoped_lock lock(mutex_); |
1481 | 1577 |
1482 std::list<int64_t> id; | 1578 std::list<int64_t> id; |
1483 db_->LookupTagValue(id, tag, value); | 1579 db_->LookupTagValue(id, tag, value); |
1484 | 1580 |
1485 for (std::list<int64_t>::const_iterator | 1581 for (std::list<int64_t>::const_iterator |
1486 it = id.begin(); it != id.end(); it++) | 1582 it = id.begin(); it != id.end(); ++it) |
1583 { | |
1584 if (db_->GetResourceType(*it) == type) | |
1585 { | |
1586 result.push_back(db_->GetPublicId(*it)); | |
1587 } | |
1588 } | |
1589 } | |
1590 | |
1591 | |
1592 void ServerIndex::LookupTagValue(std::list<std::string>& result, | |
1593 DicomTag tag, | |
1594 const std::string& value) | |
1595 { | |
1596 result.clear(); | |
1597 | |
1598 boost::mutex::scoped_lock lock(mutex_); | |
1599 | |
1600 std::list<int64_t> id; | |
1601 db_->LookupTagValue(id, tag, value); | |
1602 | |
1603 for (std::list<int64_t>::const_iterator | |
1604 it = id.begin(); it != id.end(); ++it) | |
1487 { | 1605 { |
1488 result.push_back(db_->GetPublicId(*it)); | 1606 result.push_back(db_->GetPublicId(*it)); |
1489 } | 1607 } |
1490 } | 1608 } |
1491 | 1609 |
1499 | 1617 |
1500 std::list<int64_t> id; | 1618 std::list<int64_t> id; |
1501 db_->LookupTagValue(id, value); | 1619 db_->LookupTagValue(id, value); |
1502 | 1620 |
1503 for (std::list<int64_t>::const_iterator | 1621 for (std::list<int64_t>::const_iterator |
1504 it = id.begin(); it != id.end(); it++) | 1622 it = id.begin(); it != id.end(); ++it) |
1505 { | 1623 { |
1506 result.push_back(db_->GetPublicId(*it)); | 1624 result.push_back(db_->GetPublicId(*it)); |
1507 } | 1625 } |
1508 } | 1626 } |
1627 | |
1628 | |
1629 StoreStatus ServerIndex::AddAttachment(const FileInfo& attachment, | |
1630 const std::string& publicId) | |
1631 { | |
1632 boost::mutex::scoped_lock lock(mutex_); | |
1633 | |
1634 Transaction t(*this); | |
1635 | |
1636 ResourceType resourceType; | |
1637 int64_t resourceId; | |
1638 if (!db_->LookupResource(publicId, resourceId, resourceType)) | |
1639 { | |
1640 return StoreStatus_Failure; // Inexistent resource | |
1641 } | |
1642 | |
1643 // Remove possible previous attachment | |
1644 db_->DeleteAttachment(resourceId, attachment.GetContentType()); | |
1645 | |
1646 // Locate the patient of the target resource | |
1647 int64_t patientId = resourceId; | |
1648 for (;;) | |
1649 { | |
1650 int64_t parent; | |
1651 if (db_->LookupParent(parent, patientId)) | |
1652 { | |
1653 // We have not reached the patient level yet | |
1654 patientId = parent; | |
1655 } | |
1656 else | |
1657 { | |
1658 // We have reached the patient level | |
1659 break; | |
1660 } | |
1661 } | |
1662 | |
1663 // Possibly apply the recycling mechanism while preserving this patient | |
1664 assert(db_->GetResourceType(patientId) == ResourceType_Patient); | |
1665 Recycle(attachment.GetCompressedSize(), db_->GetPublicId(patientId)); | |
1666 | |
1667 db_->AddAttachment(resourceId, attachment); | |
1668 | |
1669 t.Commit(attachment.GetCompressedSize()); | |
1670 | |
1671 return StoreStatus_Success; | |
1672 } | |
1673 | |
1674 | |
1675 void ServerIndex::DeleteAttachment(const std::string& publicId, | |
1676 FileContentType type) | |
1677 { | |
1678 boost::mutex::scoped_lock lock(mutex_); | |
1679 listener_->Reset(); | |
1680 | |
1681 Transaction t(*this); | |
1682 | |
1683 ResourceType rtype; | |
1684 int64_t id; | |
1685 if (!db_->LookupResource(publicId, id, rtype)) | |
1686 { | |
1687 throw OrthancException(ErrorCode_UnknownResource); | |
1688 } | |
1689 | |
1690 db_->DeleteAttachment(id, type); | |
1691 | |
1692 t.Commit(0); | |
1693 } | |
1694 | |
1695 | |
1509 } | 1696 } |