From eaab4d3fd6b7a330c1b904dc69d7ea4f0fbe8781 Mon Sep 17 00:00:00 2001 From: Michael Barton Date: Thu, 18 Sep 2014 19:20:51 +0000 Subject: [PATCH] container.merge_items bug When replicated container entries get round-tripped through json, they wind up with unicode objects for names. This causes equality checks to fail against container entries, and you can wind up with duplicate records. My bad. Change-Id: I3aee2ad8dbd3a617efe37e887cfb902a3e4a1646 --- swift/container/backend.py | 4 ++++ test/unit/container/test_backend.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/swift/container/backend.py b/swift/container/backend.py index abb5107c48..a053b1643a 100644 --- a/swift/container/backend.py +++ b/swift/container/backend.py @@ -682,6 +682,10 @@ class ContainerBroker(DatabaseBroker): 'storage_policy_index'} :param source: if defined, update incoming_sync with the source """ + for item in item_list: + if isinstance(item['name'], unicode): + item['name'] = item['name'].encode('utf-8') + def _really_merge_items(conn): curs = conn.cursor() if self.get_db_version(conn) >= 1: diff --git a/test/unit/container/test_backend.py b/test/unit/container/test_backend.py index c2d7208ba1..6a21a3afab 100644 --- a/test/unit/container/test_backend.py +++ b/test/unit/container/test_backend.py @@ -26,6 +26,7 @@ from collections import defaultdict from contextlib import contextmanager import sqlite3 import pickle +import json from swift.container.backend import ContainerBroker from swift.common.utils import Timestamp @@ -1202,6 +1203,33 @@ class TestContainerBroker(unittest.TestCase): self.assertEquals(['a', 'b', 'c'], sorted([rec['name'] for rec in items])) + def test_merge_items_overwrite_unicode(self): + # test DatabaseBroker.merge_items + snowman = u'\N{SNOWMAN}'.encode('utf-8') + broker1 = ContainerBroker(':memory:', account='a', container='c') + broker1.initialize(Timestamp('1').internal, 0) + id = broker1.get_info()['id'] + broker2 = ContainerBroker(':memory:', account='a', container='c') + broker2.initialize(Timestamp('1').internal, 0) + broker1.put_object(snowman, Timestamp(2).internal, 0, + 'text/plain', 'd41d8cd98f00b204e9800998ecf8427e') + broker1.put_object('b', Timestamp(3).internal, 0, + 'text/plain', 'd41d8cd98f00b204e9800998ecf8427e') + broker2.merge_items(json.loads(json.dumps(broker1.get_items_since( + broker2.get_sync(id), 1000))), id) + broker1.put_object(snowman, Timestamp(4).internal, 0, 'text/plain', + 'd41d8cd98f00b204e9800998ecf8427e') + broker2.merge_items(json.loads(json.dumps(broker1.get_items_since( + broker2.get_sync(id), 1000))), id) + items = broker2.get_items_since(-1, 1000) + self.assertEquals(['b', snowman], + sorted([rec['name'] for rec in items])) + for rec in items: + if rec['name'] == snowman: + self.assertEquals(rec['created_at'], Timestamp(4).internal) + if rec['name'] == 'b': + self.assertEquals(rec['created_at'], Timestamp(3).internal) + def test_merge_items_overwrite(self): # test DatabaseBroker.merge_items broker1 = ContainerBroker(':memory:', account='a', container='c')